/*
 * 代号：凤凰
 * http://www.jphenix.org
 * 2014-06-04
 * V4.0
 */
package com.jphenix.service.db.common.instancea;

import com.jphenix.driver.log.xlogc.XLogFilter;
import com.jphenix.driver.serialno.FSN;
import com.jphenix.driver.threadpool.ThreadSession;
import com.jphenix.kernel.baseobject.instanceb.ABase;
import com.jphenix.service.db.datamanager.instancea.ConnectionImpl;
import com.jphenix.service.db.datamanager.interfaceclass.IDataManager;
import com.jphenix.service.db.exception.DBException;
import com.jphenix.service.db.util.DBUtil;
import com.jphenix.share.lang.*;
import com.jphenix.share.util.BaseUtil;
import com.jphenix.share.util.DebugUtil;
import com.jphenix.share.util.StringUtil;
import com.jphenix.standard.db.IBlobOuter;
import com.jphenix.standard.db.IDBQuery;
import com.jphenix.standard.db.IDataDict;
import com.jphenix.standard.db.QueryPageVO;
import com.jphenix.standard.docs.ClassInfo;
import com.jphenix.standard.serialno.ISN;

import java.io.*;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.*;

//#region 注释区
/**
 * 数据库操作类
 * com.jphenix.service.db.common.instancea.DBQuery
 * 
 * Oracle 等主流数据库
 * 
 * 注意：关于数据字典数组，不能讲脚本主键传进来，这样脚本管理类无法识别出当前整型数据库操作的脚本引用了这些数据字典脚本
 * 
 * 2018-05-17 修改了一下输入日志，突出显示sql语句
 * 2018-08-01 增加了分页查询方法，直接传入页号和每页记录数
 * 2018-08-16 分页查询做字典处理时，将分页信息类也传入其中 
 * 2018-08-17 拼装获取记录数语句时，如果其中存在orderby语句，在Mssql数据库中执行会报错
 * 2019-02-14 增加了查询并返回字符串方法，增加了分隔符参数
 * 2019-03-06 简化了程序代码
 * 2019-03-08 解决了一个因为简化代码导致自己调用自己的bug
 * 2019-03-15 增加了可以将数据库操作语句，输出到自定义日志文件中
 *            又解决了一个在调试时发现的错误
 * 2019-04-09 用SDouble替代了SFloat
 * 2019-05-14 解决了qi方法输出日志中，记录集数量显示错误的问题
 *            解决了获取数据库连接时，传参错误的问题
 *            查询方法不走数据库会话
 * 2019-06-18 将数据库信息服务迁移到DBQuery中了，目的是可以更新表状态
 * 2019-06-21 传入分页信息的方法，在每页记录数为-1时，不做分页处理
 * 2019-06-26 修改了序列号生成器的构造方法
 * 2019-08-13 增加了exec方法调用存储过程返回记录集
 * 2019-08-14 修改了自动拼装获取记录数语句时，如果语句末尾是分号，拼装取数语句错误的问题
 * 2019-08-31 如果启用了事务，查询方法也要获取事务链接，因为可能在事务处理时，先插入数据，
 *            再查询刚才插入的数据。如果查询操作不走事务，就无法查询到刚才插入的数据，导致报错。
 * 2019-09-11 增加了字典数组中支持 SListMap<Map<String,String>>字典元素 key为字段名  value字典值对照容器，对照值的字段主键为 原字段主键_dict
 *            去掉了被转义的新字典名后缀_dict。如果查询结果中既想保留字典主键，又想保留转义的字典值，不妨查询出两个字典主键，其中一个字典主键起个别名
 *            提取了拼装语句值的方法到接口中
 * 2019-11-18 增加了单次查询超时时间设置
 * 2020-09-05 不分页查询记录集方法，增加了传入记录集序列，将查询后的记录集直接放入传入参数中
 * 2020-09-09 在查询方法中，在处理记录集之前，先初始化所有字典类实例
 * 2020-11-24 为了支持jdbc通过impala调用kudu库，增加了构建会话对象的方法
 * 2021-06-29 解决了分页查询时，重复往字段名序列中插入值
 * 2022-06-22 去掉了重复名的，入参中提交参数为String[]的方法
 * 2022-11-16 简化了日志
 * 2024-05-21 修改了执行特殊sql语句时，解析表名时抛异常的问题
 * 2024-06-10 提取出fixSqlInfo方法到静态工具类，供其他类使用
 * 2024-08-14 新增 ql(sql) 方法，在实际使用时用到这个方法了
 * 
 * @author 刘虻
 * 2011-6-2 下午03:14:36
 */
//#endregion
@ClassInfo({"2024-08-14 19:43","数据库操作类"})
public class DBQuery extends ABase implements IDBQuery {

	//#region 变量声明区
	private   DBQuerySvc   dbs                  = null; // 数据库信息服务
	protected String       dataSourceName       = null; // 数据源主键
	protected ISN          sn                   = null; // 主键生成类
	protected IDataManager dataManager          = null; // 数据库连接管理类
	private   boolean      outLog               = true; // 是否输出日志到控制台
	private   String       logFileKey           = null; // 如果需要单独保存到自定义日志文件中，该值为日志文件名（不带扩展名）
    private   Integer      prepareStatementType = null; // 构建事务时的类型，默认传2个参数
    //#endregion
    
    //#region 构造函数
	/**
	 * 构造函数
	 * @author 刘虻
	 */
	public DBQuery() {
		super();
	}
	//#endregion

	//#region setDataSource 设置数据源主键
	/**
	 * 设置数据源主键
	 * @param dsName 数据源主键
	 * 2014-3-8
	 * @author 马宝刚
	 */
	@Override
	public void setDataSource(String dsName) {
		this.dataSourceName = dsName;
		initLog(); //尝试初始化日志输出开关
    }
	//#endregion
  
	//#region getPrepareStatementType 获取构建事务的类型
	public int getPrepareStatementType(){
		if(prepareStatementType==null){
			//从配置文件中获取
			String spType = dataManager.getElementInfoMap(dataSourceName).get("paraStatementType");
			if(spType!=null && spType.length()>0){
				prepareStatementType = SInteger.valueOf(spType);
			}else{
				prepareStatementType = 2; 
			}
		}
		return prepareStatementType;
	}
	//#endregion

	//#region setDataManager 设置数据库连接管理类
	/**
	 * 设置数据库连接管理类
	 * 刘虻
	 * 2011-6-2 下午03:38:43
	 * @param dataManager 数据库连接管理类
	 */
	public void setDataManager(IDataManager dataManager) {
		this.dataManager = dataManager;
		initLog(); //尝试初始化日志输出开关
	}
	//#endregion

	//#region initLog 初始化日志开关
	/**
	 * 初始化日志开关
	 * 2019年3月6日
	 * @author MBG
	 */
	private void initLog() {
		if(dataSourceName==null || dataSourceName.length()<1) {
			return;
		}
		if(dataManager==null) {
			return;
		}
		//获取该数据源对应的配置信息
		Map<String,String> infoMap = dataManager.getElementInfoMap(dataSourceName);
		if(infoMap==null) {
			return;
		}
		outLog     = !boo(infoMap.get("db_log_no_out_console"));
		logFileKey = infoMap.get("db_log_file_key");

		if(logFileKey!=null && logFileKey.length()>0) {
			//放入自定义日志文件名，否则不会自动建立文件
			XLogFilter xlogFilter = bean(XLogFilter.class);
			if(xlogFilter!=null) {
				xlogFilter.addCustomLogFileKeys(logFileKey);
			}
		}
	}
	//#endregion

	//#region getSourceType 获取当前数据源类型
	/**
	 * 获取当前数据源类型
	 * @return 当前数据源类型
	 * 2014年9月24日
	 * @author 马宝刚
	 */
	@Override
	public String getSourceType() {
		return SString.valueOf(dataManager.getDataSourceType(dataSourceName));
	}
	//#endregion

	//#region getSourceName 获取数据源主键
	/**
	 * 获取数据源主键
	 * @return 数据源主键
	 * 2014年9月24日
	 * @author 马宝刚
	 */
	@Override
	public String getSourceName() {
		return dataSourceName;
	}
	//#endregion

	//#region getParameterType 针对PostgreSQL提交值必须针对不同类型提交
	/**
	 * 针对PostgreSQL提交值必须针对不同类型提交
	 * 
	 * 注意：因为这个数据库比较冷门，暂时需要那种类型，再加哪种类型
	 * 
	 * @param param  提交值类实例
	 * @return       提交值的类型
	 * 2016年5月23日
	 * @author MBG
	 */
	protected int getParameterType(Object param) {
		if(param==null) {
			return Types.NULL;
		}
		if(param instanceof Character) {
			return Types.CHAR;
		}
		if(param instanceof Integer) {
			return Types.INTEGER;
		}
		if(param instanceof Double) {
			return Types.DOUBLE;
		}
		if(param instanceof Float) {
			return Types.FLOAT;
		}
		return Types.VARCHAR;
	}
	//#endregion

	//#region fixPreparedStatement 将值放入事务中
	/**
	 * 将值放入事务中
	 * @author 刘虻
	 * @param stmt 事务
	 * @param fieldObjectArrl 值序列 
	 * @return 插入值日志信息
	 * 2006-3-30 19:44:40
	 * @throws SQLException 设置值时发生异常
	 */
	@Override
	public String fixPreparedStatement(
			PreparedStatement stmt,Object[] params) throws Exception {
		// 导入参数合法化（必要）
		if (stmt==null || params==null || params.length<1 ) {
			return "";
		}
		//构建返回值
		StringBuffer reSbf = new StringBuffer();
		int type; //参数值类型
		for (int i=0;i<params.length;i++) {
			//设置传入值
			type = getParameterType(params[i]);
			if(type==Types.VARCHAR) {
				if(params[i]==null) {
					reSbf.append("+++Set Property"+(i+1)+":{NULL}\n");
					stmt.setNull(i+1, Types.VARCHAR);
				}else {
					reSbf.append("+++Set Property"+(i+1)+":["+params[i]+"]\n");
					String strValue = str(params[i]); //提交值
					try {
						stmt.setString(i+1,strValue);
					}catch(SQLException e) {
						//Oracle 大于2000个字节总是报错
						stmt.setCharacterStream(i+1,new StringReader(strValue),strValue.length());
					}
				}
			}else if(type==Types.DOUBLE) {
				//转换为浮点型
				double doubleValue = 0;
				try {
					doubleValue = SDouble.valueOf(params[i]);
				}catch(Exception e) {
					e.printStackTrace();
					throw new SQLException("Fix Double Exception");
				}
				reSbf.append("Set Property "+(i+1)+":["+doubleValue+"]\n");
				//设置值
				stmt.setDouble(i+1,doubleValue);
			}else if(type==Types.INTEGER) {
				reSbf.append("Set Property"+(i+1)+":["+SInteger.valueOf(params[i]+"]\n"));
				stmt.setInt(i+1, SInteger.valueOf(params[i]));
			}else if(type==Types.FLOAT) {
				//转换为浮点型
				double doubleValue = 0;
				try {
					doubleValue = SDouble.valueOf(params[i]);
				}catch(Exception e) {
					e.printStackTrace();
					throw new SQLException("Fix Float Exception");
				}
				reSbf.append("Set Property "+(i+1)+":["+doubleValue+"]\n");
				//设置值
				stmt.setFloat(i+1,(float)doubleValue);
			}
		}
		return reSbf.toString();
	}
	//#endregion

	//#region setSN 设置序列号生成器
	/**
	 * 设置序列号生成器
	 * 刘虻
	 * 2011-6-2 下午03:37:19
	 * @param sn 序列号生成器
	 */
	public void setSN(ISN sn) {
		this.sn = sn;
	}
	//#endregion

	//#region getSN 获取序列号生成器
	/**
	 * 获取序列号生成器
	 * @return 序列号生成器
	 * 2016年12月11日
	 * @author MBG
	 */
	public ISN getSN() {
		if(sn==null) {
			//主键长度
			int snSize = sint(prop.getParameter("db/sn_size"));
			if(snSize<1) {
				snSize = 20;
			}
			sn = FSN.newInstance(snSize);
		}
		return sn;
	}
	//#endregion

	//#region e 执行更新 全称 executeUpdate
	/**
	 * 执行更新 全称 executeUpdate
	 * 
	 * 根据不同类型的提交值设置不同值
	 * 
	 * @param sql                       更新语句
	 * @param params                更新值数组
	 * @return                          返回更新状态
	 * @throws Exception            异常
	 * 2014-3-8
	 * @author 马宝刚
	 */
	@Override
	public int e(String sql, Object[] params) throws Exception {
		return executeUpdate(sql,params);
	}
	//#endregion

	//#region executeUpdate 执行更新
	/**
	 * 执行更新
	 * @param sql 更新语句
	 * @return 更新记录数
	 * @throws Exception 异常
	 * 2015年11月28日
	 * @author 马宝刚
	 */
	@Override
	public int executeUpdate(String sql) throws Exception {
		return executeUpdate(sql,(List<String>)null);
	}
	//#endregion

	//#region e 执行更新 全称：executeUpdate
	/**
	 * 执行更新 全称：executeUpdate
	 * @param sql 更新语句
	 * @return 更新记录数
	 * @throws Exception 异常
	 * 2015年11月28日
	 * @author 马宝刚
	 */
	@Override
	public int e(String sql) throws Exception {
		return executeUpdate(sql,(List<String>)null);
	}
	//#endregion

	//#region e 执行更新 全称 executeUpdate
	/**
	 * 执行更新 全称 executeUpdate
	 * @param sql                       更新语句
	 * @param uValueArrl            更新值序列
	 * @return                          返回更新状态
	 * @throws Exception            异常
	 * 2014-3-8
	 * @author 马宝刚
	 */
	@Override
	public int e(String sql, List<String> uValueArrl) throws Exception {
		return executeUpdate(sql,uValueArrl);
	}
	//#endregion

	//#region exec 以exec方式执行存储过程
	/**
	 * 以exec方式执行存储过程
	 * @param sql         调用存储过程的语句
	 * @param paras       提交参数数组
	 * @return            返回记录及
	 * @throws Exception  异常
	 * 2019年8月13日
	 * @author MBG
	 */
	@Override
	public List<Map<String,String>> exec(String sql, Object[] paras) throws Exception {
		//构建返回值
		List<Map<String,String>> resArrl = new ArrayList<Map<String,String>>();
		if (sql == null || sql.length()<1) {
			return resArrl;
		}
		List<String>           paraList = StringUtil.strs2list(paras); //转换参数格式
		Connection             conn     = null; // 连接对象
		CallableStatement      stmt     = null; // 事务
		ResultSet              rs       = null; // 记录集
		ResultSetMetaData      metaData = null; // 获取字段信息
		HashMap<String,String> hasm;            // 行记录集容器
		Object                 columnValue;     // 字段值
		Integer                timeOut  = null; // 查询超时时间（秒）
		try {
			conn = getConn(null);      //获取数据库连接
			sql  = DBUtil.fixSqlWithPara(sql,paraList);
			stmt = conn.prepareCall(sql);       //获取事务
			String parasLog = DBUtil.fixPreparedStatement(stmt,paraList); // 设置值
			long beforeTime = System.currentTimeMillis(); //记录执行开始时间
			// 查询超时时间（秒）
			timeOut = sint(ThreadSession.get("DB_QUERY_TIME_OUT"));
			if(timeOut>0) {
				stmt.setQueryTimeout(timeOut);
			}
			stmt.execute(); //执行脚本
			rs = stmt.getResultSet(); //获取存储过程返回的记录集
			try {
				//调用存储过程后没有返回记录集，此动作会抛异常
				metaData = rs.getMetaData();
			}catch(Exception e) {}
			if (metaData!=null) {
				//获取字段数量
				int colCountInt = metaData.getColumnCount();
				//字段名数组
				String[] fieldNames = new String[colCountInt];
				for(int i=0;i<colCountInt;i++) {
					fieldNames[i] = str(metaData.getColumnLabel(i+1)).toLowerCase();
					if(fieldNames[i].length()<1) {
						fieldNames[i] = str(metaData.getColumnName(i+1)).toLowerCase();
					}
				}
				while (rs.next()) {
					//构造行记录集容器
					hasm = new HashMap<String,String>();
					for (int i=0; i<colCountInt; i++) {
						//获取字段值
						columnValue = rs.getObject(fieldNames[i]);
						if (columnValue instanceof Clob) {
							hasm.put(fieldNames[i],DBUtil.getClobString(((Clob)columnValue)));
						}else if(columnValue instanceof byte[]) {
							//mysql 在语句中使用函数时，有时会将本应该返回字符串的值返回字节数组
							hasm.put(fieldNames[i],new String((byte[])columnValue));
						}else {
							if(columnValue==null){
								columnValue = "";
							}
							hasm.put(fieldNames[i],columnValue.toString());
						}
					}
					resArrl.add(hasm);
				}
			}
			log.sqlLog(" DataSource:["+dataSourceName+"] Query Info:+++Result Count[" 
					+ resArrl.size() + "] Use Time:["+SDate.showMillisecond(System.currentTimeMillis()-beforeTime)+"] SQL:[\n"+sql+"\n] "+
					parasLog,outLog,logFileKey);
			return resArrl;
		}catch(Exception e){
			e.printStackTrace();
			log.error("queryList Exception Sql:[\n"+sql+"\n] uList:["+StringUtil.arr2str(paras,",")+"]",e);
			try {
				//执行回滚
				conn.rollback();
			}catch(Exception e2) {}
			throw e;
		}finally{
			try {
				rs.close();
			} catch (Exception e2) {}
			rs = null;
			try {
				stmt.close();
			} catch (Exception e2) {}
			stmt = null;
			try {
				conn.close();
			} catch (Exception e2) {}
			conn = null;
		}
	}
	//#endregion

	//#region executeUpdate 执行处理语句
	/**
	 * 覆盖方法
	 * 刘虻
	 * 2011-6-2 下午03:14:36
	 */
	@Override
	public int executeUpdate(String sql, List<String> uList) throws Exception {
		if (sql == null || sql.length()<1) {
			return -1;
		}
		String            tbName  = getTableName(sql); // 更新语句中要操作的表名
		Connection        conn    = null;              // 数据库连接对象
		PreparedStatement stmt    = null;              // 数据库事务对象
		Integer           timeOut = null;              // 查询超时时间（秒）
		try {
			conn = getConn(null);
			sql  = DBUtil.fixSqlWithPara(sql,uList); // 处理语句中的 (#)关键字
			stmt = conn.prepareStatement(sql);

			String parasLog = DBUtil.fixPreparedStatement(stmt, uList); // 设置值
			long beforeTime = System.currentTimeMillis(); //记录执行开始时间
			// 查询超时时间（秒）
			timeOut = sint(ThreadSession.get("DB_QUERY_TIME_OUT"));
			if(timeOut>0) {
				stmt.setQueryTimeout(timeOut);
			}
			int res =  stmt.executeUpdate(); //执行脚本并获取返回值
			log.sqlLog(" DataSource:["+dataSourceName+"] TableName:["+tbName+"] ExecuteUpdate Res:["+res+"]  timeOut:["+timeOut+"] Use Time:[" 
					+ SDate.showMillisecond(System.currentTimeMillis()-beforeTime)+ "] SQL:[\n"+sql+"\n] "+parasLog,outLog,logFileKey);
			return res;
		} catch (Exception e) {
			e.printStackTrace();
			log.error("executeUpdate Exception TableName:["+tbName+"] Sql:[\n"+sql+"\n] uList:["+DebugUtil.getListValue(uList," ")+"] dsName:["+dataSourceName+"]",e);
			try {
				//执行回滚
				conn.rollback();
			}catch(Exception e2) {}
			throw e;
		} finally {
			try {
				stmt.close();
			}catch(Exception e1) {}
			stmt = null;
			try {
				conn.close();
			}catch(Exception e2) {}
			conn = null;
			if(tbName.length()>0) {
				getDbs().refreshTableState(tbName,dataSourceName);
			}
		}
	}
	//#endregion

	//#region insert 执行插入语句，并获取插入后的自增主键值
	/**
	 * 执行插入语句，并获取插入后的自增主键值
	 * @param infos 脚本中采用 <%SQL$  语句     $SQL%> 拼装的信息
	 * @return 自增主键值
	 * @throws Exception 异常
	 * 2017年4月18日
	 * @author MBG
	 */
	@Override
	@SuppressWarnings("unchecked")
	public int insert(Object[] infos) throws Exception {
		//0 sql语句   1 List<String> 提交值
		Object[] fixInfos = DBUtil.fixSqlInfo(log,infos); //整理传入值
		if(fixInfos==null || fixInfos.length<1 
				|| fixInfos[0]==null || ((String)fixInfos[0]).length()<1) {
			//验证传入信息
			return -1;
		}
		Connection        conn    = null;
		PreparedStatement stmt    = null;
		Integer           timeOut = null;
		try {
			conn = getConn(null);
			//构建带返回新增主键值的事务处理类
			int pType = getPrepareStatementType();
			if(pType==0){
				stmt = conn.prepareStatement((String)fixInfos[0]);
			}else{
				stmt = conn.prepareStatement((String)fixInfos[0],Statement.RETURN_GENERATED_KEYS);
			}
			String parasLog = DBUtil.fixPreparedStatement(stmt,(List<String>)fixInfos[1]); // 设置值
			long beforeTime = System.currentTimeMillis(); //记录执行开始时间
			//查询超时时间（秒）
			timeOut = sint(ThreadSession.get("DB_QUERY_TIME_OUT"));
			if(timeOut>0) {
				stmt.setQueryTimeout(timeOut);
			}
			stmt.executeUpdate(); //执行语句
			int res = -1; //新增主键值
			//获取新增主键记录
			ResultSet rs = stmt.getGeneratedKeys();
			if(rs!=null && rs.next()) {
				res = rs.getInt(1);
			}
			log.sqlLog(" DataSource:[\n"+dataSourceName+"\n] ExecuteUpdate PrimaryKeyValue:["
					+res+"] SQL:[\n"+fixInfos[0]+"\n] params:["+parasLog+"] timeOut:["+timeOut+"] Use Time:["+
					SDate.showMillisecond(System.currentTimeMillis()-beforeTime)+ "] ",outLog,logFileKey);
			return res;
		} catch (Exception e) {
			e.printStackTrace();
			log.error("executeUpdate Exception Sql:[\n"+fixInfos[0]+"\n] uList:["+DebugUtil.getListValue((List<String>)fixInfos[1])+"] dsName:["+dataSourceName+"]",e);
			try {
				//执行回滚
				conn.rollback();
			}catch(Exception e2) {}
			throw e;
		} finally {
			try {
				stmt.close();
			}catch(Exception e1) {}
			stmt = null;
			try {
				conn.close();
			}catch(Exception e2) {}
			conn = null;
		}
	}
	//#endregion

	//#region executeUpdate 执行更新
	/**
	 * 覆盖方法
	 * 刘虻
	 * 2011-6-2 下午03:14:36
	 */
	@Override
	public int executeUpdate(String sql, Object[] params) throws Exception {
		if(sql == null|| sql.length()<1) {
			return -1;
		}
		String            tbName  = getTableName(sql); // 操作数据涉及到的表名
		Connection        conn    = null;              // 数据库连接对象
		PreparedStatement stmt    = null;              // 数据库事务对象
		Integer           timeOut = null;              // 查询超时时间（秒）
		try {
			conn = getConn(null);
			Object[] reses = DBUtil.fixSqlWithPara(sql,params); //处理语句中的 (#)关键字
			sql    = str(reses[0]);
			params = (Object[])reses[1];
			stmt   = conn.prepareStatement(sql);
			String parasLog = fixPreparedStatement(stmt, params); // 设置值
			long beforeTime = System.currentTimeMillis(); //记录执行开始时间
			// 查询超时时间（秒）
			timeOut = sint(ThreadSession.get("DB_QUERY_TIME_OUT"));
			if(timeOut>0) {
				stmt.setQueryTimeout(timeOut);
			}
			int res =  stmt.executeUpdate(); //执行脚本并获取返回值
			log.sqlLog(" DataSource:["+dataSourceName+"] TableName:["+tbName+"] ExecuteUpdate Res:["+res+"]  Use Time:[" 
					+ SDate.showMillisecond(System.currentTimeMillis()-beforeTime)+ "] timeOut:["+timeOut+"] SQL:[\n"+sql+"\n] "+parasLog,outLog,logFileKey);
			return res;
		} catch (Exception e) {
			e.printStackTrace();
			log.error("executeUpdate Exception TableName:["+tbName+"] Sql:[\n"+sql+"\n] uList:["
					+DebugUtil.getArrayString(params)+"] dsName:["+dataSourceName+"]",e);
			try {
				//执行回滚
				conn.rollback();
			}catch(Exception e2) {}
			throw e;
		} finally {
			try {
				stmt.close();
			}catch(Exception e1) {}
			stmt = null;
			try {
				conn.close();
			}catch(Exception e2) {}
			conn = null;
			if(tbName.length()>0) {
				getDbs().refreshTableState(tbName,dataSourceName);
			}
		}
	}
	//#endregion

	//#region queryOne 查询结果并返回第一条记录
	/**
	 * 查询结果并返回第一条记录
	 * @param sql          查询语句
	 * @param uValueArrl    提交值素组
	 * @return            记录集行对象
	 * @throws Exception    异常
	 * 2014-3-8
	 * @author 马宝刚
	 */
	@Override
	public Map<String,String> queryOne(String sql, Object[] uValueArrl) throws Exception {
		//构建传入参数
		List<String> uList = new ArrayList<String>();
		if(uValueArrl!=null) {
			for(Object ele:uValueArrl) {
				uList.add(ele==null?null:SString.valueOf(ele));
			}
		}
		return queryOne(sql,uList,null);
	}
	//#endregion

	//#region o 查询结果并返回第一条记录
	/**
	 * 查询结果并返回第一条记录
	 * 
	 * 根据不同类型的提交值设置不同值
	 * 
	 * @param sql          查询语句
	 * @param uVlaueArrl      提交值对象数组
	 * @return            记录集行对象
	 * @throws Exception    异常
	 * 2014-3-8
	 * @author 马宝刚
	 */
	@Override
	public Map<String,String> o(String sql, Object[] paras) throws Exception {
		return queryOne(sql,paras,null);
	}
	//#endregion

	//#region o 查询结果并返回第一条记录
	/**
	 * 查询结果并返回第一条记录
	 * 
	 * 根据不同类型的提交值设置不同值
	 * 
	 * @param sql          查询语句
	 * @param uVlaueArrl      提交值对象数组
	 * @param dicts               数据字典类序列
	 * @return            记录集行对象
	 * @throws Exception    异常
	 * 2014-3-8
	 * @author 马宝刚
	 */
	@Override
	public Map<String,String> o(String sql, Object[] paras, Object[] dicts) throws Exception {
		return queryOne(sql,paras,dicts);
	}
	//#endregion

	//#region queryOne 查询结果并返回第一条记录
	/**
	 * 查询结果并返回第一条记录
	 * @param sql                   查询语句
	 * @return                      记录集行对象
	 * @throws Exception        异常
	 * 2014-3-8
	 * @author 马宝刚
	 */
	@Override
	public Map<String,String> queryOne(String sql) throws Exception {
		return queryOne(sql,(List<String>)null, null);
	}
	//#endregion

	//#region o 查询结果并返回第一条记录 全称  queryOne
	/**
	 * 查询结果并返回第一条记录 全称  queryOne
	 * @param sql                   查询语句
	 * @return                      记录集行对象
	 * @throws Exception        异常
	 * 2014-3-8
	 * @author 马宝刚
	 */
	@Override
	public Map<String,String> o(String sql) throws Exception {
		return queryOne(sql,(List<String>)null, null);
	}
	//#endregion

	//#region queryOne 查询结果并返回第一条记录
	/**
	 * 查询结果并返回第一条记录
	 * @param sql                   查询语句
	 * @param uValueArrl        提交值序列
	 * @return                      记录集行对象
	 * @throws Exception        异常
	 * 2014-3-8
	 * @author 马宝刚
	 */
	@Override
	public Map<String,String> queryOne(String sql, List<String> uValueArrl) throws Exception {
		return queryOne(sql,uValueArrl,null);
	}
	//#endregion

	//#region o 查询结果并返回第一条记录 全称 queryOne
	/**
	 * 查询结果并返回第一条记录 全称 queryOne
	 * @param sql                   查询语句
	 * @param uValueArrl        提交值序列
	 * @return                      记录集行对象
	 * @throws Exception        异常
	 * 2014-3-8
	 * @author 马宝刚
	 */
	@Override
	public Map<String,String> o(String sql, List<String> uValueArrl) throws Exception {
		return queryOne(sql,uValueArrl,null);
	}
	//#endregion

	//#region queryOne 查询结果并返回第一条记录
	/**
	 * 查询结果并返回第一条记录
	 * @param sql          查询语句
	 * @param uList        提交值序列
	 * @param dicts             数据字典类序列
	 * @return            记录集行对象
	 * @throws Exception    异常
	 * 2014-3-8
	 * @author 马宝刚
	 */
	@Override
	public Map<String,String> queryOne(String sql, List<String> uList, Object[] dicts) throws Exception {
		//构造分页查询类
		QueryPageVO qpVO = new QueryPageVO();
		qpVO.noFixPage   = true;
		qpVO.pageNo      = 1;
		qpVO.pageSize    = 1;
		qpVO.dicts       = dicts;
		qpVO.sql         = sql;
		qpVO.uList       = uList;
		queryPage(qpVO); //执行查询
		if(qpVO.rs.size()>0) {
			return qpVO.rs.get(0);
		}
		return new HashMap<String,String>();
	}
	//#endregion

	//#region queryOne 查询结果并返回第一条记录
	/**
	 * 查询结果并返回第一条记录
	 * @param sql          查询语句
	 * @param uList        提交值序列
	 * @param dicts             数据字典类序列
	 * @return            记录集行对象
	 * @throws Exception    异常
	 * 2014-3-8
	 * @author 马宝刚
	 */
	public Map<String,String> queryOne(
			String sql,Object[] paras,Object[] dicts) throws Exception {
		//构造分页查询类
		QueryPageVO qpVO = new QueryPageVO();

		qpVO.noFixPage = true;
		qpVO.pageNo = 1;
		qpVO.pageSize = 1;
		qpVO.dicts = dicts;
		qpVO.sql = sql;
		qpVO.uParas = paras;

		queryPage(qpVO); //执行查询

		if(qpVO.rs.size()>0) {
			return qpVO.rs.get(0);
		}
		return new HashMap<String,String>();
	}
	//#endregion

	//#region o 查询结果并返回第一条记录 全称 queryOne
	/**
	 * 查询结果并返回第一条记录 全称 queryOne
	 * @param sql                   查询语句
	 * @param uList             提交值序列
	 * @param dicts             数据字典类序列
	 * @return                      记录集行对象
	 * @throws Exception        异常
	 * 2014-3-8
	 * @author 马宝刚
	 */
	@Override
	public Map<String,String> o(String sql, List<String> uList, Object[] dicts) throws Exception {
		return queryOne(sql,uList,dicts);
	}
	//#endregion

	//#region queryList 查询并返回记录集序列
	/**
	 * 查询并返回记录集序列
	 * @param sql          查询语句
	 * @param uValueArrl    更新值数组
	 * @return            记录集序列
	 * @throws Exception    异常
	 * 2014-3-8
	 * @author 马宝刚
	 */
	@Override
	public List<Map<String,String>> queryList(String sql, Object[] uValueArrl) throws Exception {
		if(uValueArrl==null) {
			return queryList(sql);
		}
		return queryList(sql,uValueArrl,null);
	}
	//#endregion

	//#region q 查询并返回记录集序列
	/**
	 * 查询并返回记录集序列
	 * 
	 * 通过传入不同类型的提交值，设置不同的传入值类型
	 * 
	 * 
	 * @param sql      查询语句
	 * @param params    更新值数组
	 * @return        记录集序列
	 * @throws Exception  异常
	 * 2014-3-8
	 * @author 马宝刚
	 */
	@Override
	public List<Map<String,String>> q(String sql, Object[] params) throws Exception {
		return queryList(sql,params,null);
	}
	//#endregion

	//#region q 查询并返回记录集序列
	/**
	 * 查询并返回记录集序列
	 * 
	 * 用于不同类型的提交值，设置不同类型
	 * 
	 * 
	 * @param sql               查询语句
	 * @param params        更新值数组
	 * @param dicts             数据字典序列
	 * @return                  记录集序列
	 * @throws Exception        异常
	 * 2014-3-8
	 * @author 马宝刚
	 */
	@Override
	public List<Map<String,String>> q(String sql, Object[] params, Object[] dicts) throws Exception {
		return queryList(sql,params,dicts);
	}
	//#endregion

	//#region q 查询并返回记录集序列 全称 queryList
	/**
	 * 查询并返回记录集序列 全称 queryList
	 * @param sql                   查询语句
	 * @return                      记录集序列
	 * @throws Exception        异常
	 * 2014-3-8
	 * @author 马宝刚
	 */
	@Override
	public List<Map<String,String>> q(String sql) throws Exception {
		return queryList(sql,(Object[])null, null);
	}
	//#endregion

	//#region queryList 查询并返回记录集序列
	/**
	 * 查询并返回记录集序列
	 * @param sql                   查询语句
	 * @return                      记录集序列
	 * @throws Exception        异常
	 * 2014-3-8
	 * @author 马宝刚
	 */
	@Override
	public List<Map<String,String>> queryList(String sql) throws Exception {
		return queryList(sql,(Object[])null,null);
	}
	//#endregion

	//#region queryList 查询并返回记录集序列
	/**
	 * 查询并返回记录集序列
	 * @param sql                   查询语句
	 * @param uValueArrl        更新值序列
	 * @return                      记录集序列
	 * @throws Exception        异常
	 * 2014-3-8
	 * @author 马宝刚
	 */
	@Override
	public List<Map<String,String>> queryList(String sql, List<String> uList) throws Exception {
		return queryList(sql,uList,null,null);
	}
	//#endregion

	//#region q 查询并返回记录集序列 全称 queryList
	/**
	 * 查询并返回记录集序列 全称 queryList
	 * @param sql         查询语句
	 * @param uValueArrl  更新值序列
	 * @return            记录集序列
	 * @throws Exception  异常
	 * 2014-3-8
	 * @author 马宝刚
	 */
	@Override
	public List<Map<String,String>> q(String sql, List<String> uList) throws Exception {
		return queryList(sql,uList,null,null);
	}
	//#endregion

	//#region q 查询记录集 全称 queryList
	/**
	 * 查询记录集 全称 queryList
	 * @param sql              查询语句
	 * @param uList           查询提交值序列
	 * @param dicts           数据字典类序列
	 * @return                  查询记录集
	 * @throws Exception 异常
	 * 2014年9月25日
	 * @author 马宝刚
	 */
	@Override
	public List<Map<String,String>> q(String sql, List<String> uList, Object[] dicts) throws Exception {
		return queryList(sql,uList,dicts,null);
	}
	//#endregion

	//#region qp 执行分页查询
	/**
	 * 执行分页查询
	 * 
	 * 根据不同类型的提交值设置不同值
	 * 
	 * @param sql        查询语句（获取总数语句通过查询语句拼装而来）
	 * @param updates    提交值对象数组
	 * @return           查询结果
	 * @throws Exception 异常
	 * 2016年5月19日
	 * @author MBG
	 */
	@Override
	public QueryPageVO qp(String sql, Object[] updates) throws Exception {
		//构建返回值
		QueryPageVO qpVO = new QueryPageVO();
		qpVO.sql = sql;
		qpVO.uParas = updates;
		queryPage(qpVO);
		return qpVO;
	}
	//#endregion

	//#region queryPage 执行分页查询
	/**
	 * 执行分页查询
	 * @param sql 查询语句（获取总数语句通过查询语句拼装而来）
	 * @param updates 提交值
	 * @return 查询结果
	 * @throws Exception 异常
	 * 2016年5月19日
	 * @author MBG
	 */
	@Override
	public QueryPageVO queryPage(String sql, Object[] updates) throws Exception {
		//构建返回值
		QueryPageVO qpVO = new QueryPageVO();
		qpVO.sql = sql;
		qpVO.updates(updates);
		queryPage(qpVO);
		return qpVO;
	}
	//#endregion

	//#region qp 执行分页查询
	/**
	 * 执行分页查询
	 * 
	 * 根据不同类型的提交值设置不同值
	 * 
	 * @param sql 查询语句（获取总数语句通过查询语句拼装而来）
	 * @param updates 提交值
	 * @param dicts 字典主键对象
	 * @return 查询结果
	 * @throws Exception 异常
	 * 2016年5月19日
	 * @author MBG
	 */
	@Override
	public QueryPageVO qp(String sql,Object[] updates,Object[] dicts) throws Exception {
		//构建返回值
		QueryPageVO qpVO = new QueryPageVO();
		qpVO.sql = sql;
		qpVO.uParas = updates;
		qpVO.dicts = dicts;
		queryPage(qpVO);
		return qpVO;
	}
	//#endregion

	//#region queryPage 执行分页查询
	/**
	 * 执行分页查询
	 * @param sql 查询语句（获取总数语句通过查询语句拼装而来）
	 * @param updates 提交值
	 * @param dicts 字典主键对象
	 * @return 查询结果
	 * @throws Exception 异常
	 * 2016年5月19日
	 * @author MBG
	 */
	@Override
	public QueryPageVO queryPage(String sql,Object[] updates,Object[] dicts) throws Exception {
		//构建返回值
		QueryPageVO qpVO = new QueryPageVO();
		qpVO.sql = sql;
		qpVO.updates(updates);
		qpVO.dicts = dicts;
		queryPage(qpVO);
		return qpVO;
	}
	//#endregion

	//#region qp 执行分页查询
	/**
	 * 执行分页查询
	 * @param sql 查询语句（获取总数语句通过查询语句拼装而来）
	 * @return 查询结果
	 * @throws Exception 异常
	 * 2016年5月19日
	 * @author MBG
	 */
	@Override
	public QueryPageVO qp(String sql) throws Exception {
		//构建返回值
		QueryPageVO qpVO = new QueryPageVO();
		qpVO.sql = sql;
		queryPage(qpVO);
		return qpVO;
	}
	//#endregion

	//#region queryPage 执行分页查询
	/**
	 * 执行分页查询
	 * @param sql 查询语句（获取总数语句通过查询语句拼装而来）
	 * @return 查询结果
	 * @throws Exception 异常
	 * 2016年5月19日
	 * @author MBG
	 */
	@Override
	public QueryPageVO queryPage(String sql) throws Exception {
		//构建返回值
		QueryPageVO qpVO = new QueryPageVO();
		qpVO.sql = sql;
		queryPage(qpVO);
		return qpVO;
	}
	//#endregion
	
	//#region queryList 查询记录集
	/**
	 * 查询记录集
	 * @param sql             查询语句
	 * @param uList           查询提交值序列
	 * @param dicts           数据字典类序列
	 * @return                查询记录集
	 * @throws Exception 异常
	 * 2014年9月25日
	 * @author 马宝刚
	 */
	@Override
	public List<Map<String,String>> queryList(String sql, List<String> uList, Object[] dicts) throws Exception {
		return queryList(sql,uList,dicts,null);
	}
	//#endregion

	//#region queryList 查询记录集
	/**
	 * 查询记录集
	 * @param sql             查询语句
	 * @param uList           查询提交值序列
	 * @param dicts           数据字典类序列
	 * @param rsList          待插入数据的序列（如果存在该值，返回值也是该值）
	 * @return                查询记录集
	 * @throws Exception 异常
	 * 2014年9月25日
	 * @author 马宝刚
	 */
	@Override
	public List<Map<String,String>> queryList(String sql, List<String> uList, Object[] dicts,List<Map<String,String>> rsList) throws Exception {
		ResultSet         rs           = null;    // 记录集
		PreparedStatement stmt         = null;    // 事务
		Connection        conn         = null;    // 连接对象
		Object            columnValue;            // 字段值
		Integer           timeOut      = null;    // 查询超时时间（秒）
		try{
			conn = getConn(null);
			sql = DBUtil.fixSqlWithPara(sql,uList); //处理语句中的 (#)关键字
			//获取事务
			int pType = getPrepareStatementType();
			if(pType==0){
				stmt = conn.prepareStatement(sql);
			}else{
				stmt = 
						conn
						.prepareStatement(
								sql
								,ResultSet.TYPE_SCROLL_INSENSITIVE
								,ResultSet.CONCUR_READ_ONLY);
			}
			//设置条件值
			String paramsLog = DBUtil.fixPreparedStatement(stmt,uList);    // 设置值
			// 构造记录集容器
			if(rsList==null) {
				rsList = new ArrayList<>();
			}
			long beforeTime = System.currentTimeMillis(); //记录执行开始时间
			//查询超时时间（秒）
			timeOut = sint(ThreadSession.get("DB_QUERY_TIME_OUT"));
			if(timeOut>0) {
				stmt.setQueryTimeout(timeOut);
			}
			rs = stmt.executeQuery();        // 执行查询
			ResultSetMetaData metaData = null;    //获取字段信息
			try {
				//调用存储过程后没有返回记录集，此动作会抛异常
				metaData = rs.getMetaData();
			}catch(Exception e) {}
			if (metaData!=null) {
				//获取字段数量
				int colCountInt = metaData.getColumnCount();
				//字段名数组
				String[] fieldNames = new String[colCountInt];
				for(int i=0;i<colCountInt;i++) {
					fieldNames[i] = str(metaData.getColumnLabel(i+1)).toLowerCase();
					if(fieldNames[i].length()<1) {
						fieldNames[i] = str(metaData.getColumnName(i+1)).toLowerCase();
					}
				}
				//初始化字典类实例
				if(dicts!=null) {
					for(int i=0;i<dicts.length;i++) {
						if(dicts[i] instanceof IDataDict) {
							((IDataDict)dicts[i]).init();
						}
					}
				}
				HashMap<String,String> hasm; //行记录集容器
				while (rs.next()) {
					//构造行记录集容器
					hasm = new HashMap<String,String>();
					for (int i=0; i<colCountInt; i++) {
						//获取字段值
						columnValue = rs.getObject(fieldNames[i]);
						if (columnValue instanceof Clob) {
							hasm.put(fieldNames[i],DBUtil.getClobString(((Clob)columnValue)));
						}else if(columnValue instanceof byte[]) {
							//mysql 在语句中使用函数时，有时会将本应该返回字符串的值返回字节数组
							hasm.put(fieldNames[i],new String((byte[])columnValue));
						}else {
							if(columnValue==null){
								columnValue = "";
							}
							hasm.put(fieldNames[i],columnValue.toString());
						}
					}
					if(dicts!=null) {
						for(int i=0;i<dicts.length;i++) {
							if(dicts[i] instanceof IDataDict) {
								((IDataDict)dicts[i]).data(hasm);
							}else if(dicts[i] instanceof SListMap) {
								//强制转换为序列容器
								@SuppressWarnings("unchecked")
								SListMap<Map<String,String>> dict = (SListMap<Map<String,String>>)dicts[i];
								Map<String,String> dMap;
								for(String fEle:dict.keys()) {
									dMap = dict.get(fEle);
									if(dMap==null) {
										continue;
									}
									hasm.put(fEle,dMap.get(hasm.get(fEle)));
								}
							}
						}
					}
					rsList.add(hasm);
				}
			}
			log.sqlLog(" DataSource:["+dataSourceName+"] Query Info:+++Result Count[" 
					+ rsList.size() + "] Use Time:["+SDate.showMillisecond(System.currentTimeMillis()-beforeTime)+"] timeOut:["+timeOut+"] SQL:["+sql+"] "+paramsLog,outLog,logFileKey);
			return rsList;
		}catch(Exception e){
			e.printStackTrace();
			log.error("queryList Exception DataSource:["+dataSourceName+"] timeOut:["+timeOut+"] Sql:[\n"+sql+"\n] uList:["+DebugUtil.getListValue(uList," ")+"] dicts:["+dicts+"]",e);
			try {
				//执行回滚
				conn.rollback();
			}catch(Exception e2) {}
			throw e;
		}finally{
			try {
				rs.close();
			} catch (Exception e2) {}
			rs = null;
			try {
				stmt.close();
			} catch (Exception e2) {}
			stmt = null;
			try {
				conn.close();
			} catch (Exception e2) {}
			conn = null;
		}
	}
	//#endregion

	//#region queryList 查询记录集
	/**
	 * 查询记录集
	 * 
	 * 根据不同的提交值对象类型，设置不同的类型
	 * 
	 * @param sql        查询语句
	 * @param params     查询提交值对象数组
	 * @param dicts      数据字典类序列
	 * @return           查询记录集
	 * @throws Exception 异常
	 * 2014年9月25日
	 * @author 马宝刚
	 */
	@Override
	public List<Map<String,String>> queryList(
			String sql, Object[] params,Object[] dicts) throws Exception {
		ResultSet         rs      = null; // 记录集
		PreparedStatement stmt    = null; // 事务
		Connection        conn    = null; // 连接对象
		Integer           timeOut = null; // 查询超时时间（秒）
		try{
			conn         = getConn(null);
			Object[] res = DBUtil.fixSqlWithPara(sql,params); //处理语句中的 (#)关键字
			sql          = str(res[0]);
			params       = (Object[])res[1];
			int pType    = getPrepareStatementType();
			if(pType==0){
				stmt = conn.prepareStatement(sql);
			}else{
				//获取事务
				stmt = conn.prepareStatement(sql,
						ResultSet.TYPE_SCROLL_INSENSITIVE,
						ResultSet.CONCUR_READ_ONLY);
			}
			//设置条件值
			String                   paramsLog   = fixPreparedStatement(stmt,params); //设置值
			List<Map<String,String>> rsList      = new ArrayList<>();                 //构造记录集容器
			long                     beforeTime  = System.currentTimeMillis();        //记录执行开始时间
			// 查询超时时间（秒）
			timeOut = sint(ThreadSession.get("DB_QUERY_TIME_OUT"));
			if(timeOut>0) {
				stmt.setQueryTimeout(timeOut);
			}
			rs = stmt.executeQuery();        // 执行查询
            ResultSetMetaData metaData = null;    //获取字段信息
			try {
				//调用存储过程后没有返回记录集，此动作会抛异常
				metaData = rs.getMetaData();
			}catch(Exception e) {}
			if (metaData!=null) {
				//获取字段数量
				int colCountInt = metaData.getColumnCount();
				//字段名数组
				String[] fieldNames = new String[colCountInt];
				for(int i=0;i<colCountInt;i++) {
					fieldNames[i] = str(metaData.getColumnLabel(i+1)).toLowerCase();
					if(fieldNames[i].length()<1) {
						fieldNames[i] = str(metaData.getColumnName(i+1)).toLowerCase();
					}
				}
				//初始化字典类实例
				if(dicts!=null) {
					for(int i=0;i<dicts.length;i++) {
						if(dicts[i] instanceof IDataDict) {
							((IDataDict)dicts[i]).init();
						}
					}
				}
				while (rs.next()) {
					//构造行记录集容器
					HashMap<String,String> hasm = new HashMap<String,String>();
					for (int i=0; i<colCountInt; i++) {
						//获取字段值
						Object columnValue = rs.getObject(fieldNames[i]);
						if (columnValue instanceof Clob) {
							hasm.put(fieldNames[i],DBUtil.getClobString(((Clob)columnValue)));
						}else if(columnValue instanceof byte[]) {
							//mysql 在语句中使用函数时，有时会将本应该返回字符串的值返回字节数组
							hasm.put(fieldNames[i],new String((byte[])columnValue));
						}else {
							if(columnValue==null){
								columnValue = "";
							}
							hasm.put(fieldNames[i],columnValue.toString());
						}
					}
					if(dicts!=null) {
						for(int i=0;i<dicts.length;i++) {
							if(dicts[i] instanceof IDataDict) {
								((IDataDict)dicts[i]).data(hasm);
							}else if(dicts[i] instanceof SListMap) {
								//强制转换为序列容器
								@SuppressWarnings("unchecked")
								SListMap<Map<String,String>> dict = (SListMap<Map<String,String>>)dicts[i];
								Map<String,String> dMap;
								for(String fEle:dict.keys()) {
									dMap = dict.get(fEle);
									if(dMap==null) {
										continue;
									}
									hasm.put(fEle,dMap.get(hasm.get(fEle)));
								}
							}
						}
					}
					rsList.add(hasm);
				}
			}
			log.sqlLog(" DataSource:["+dataSourceName+"] Query Info:+++Result Count[" 
					+ rsList.size() + "] Use Time:["+SDate.showMillisecond(System.currentTimeMillis()-beforeTime)+"] timeOut:["+timeOut+"] SQL:[\n"+sql+"\n] "+paramsLog,outLog,logFileKey);
			return rsList;
		}catch(Exception e){
			e.printStackTrace();
			log.error("queryList DataSource:["+dataSourceName+"] timeOut:["+timeOut+"] Exception Sql:[\n"+sql+"\n] uList:["+DebugUtil.getArrayString(params)+"] dicts:["+dicts+"]",e);
			try {
				//执行回滚
				conn.rollback();
			}catch(Exception e2) {}
			throw e;
		}finally{
			try {
				rs.close();
			} catch (Exception e2) {}
			rs = null;
			try {
				stmt.close();
			} catch (Exception e2) {}
			stmt = null;
			try {
				conn.close();
			} catch (Exception e2) {}
			conn = null;
		}
	}
	//#endregion

	//#region c 调用存储过程 全称 call
	/**
	 * 调用存储过程 全称 call
	 * @param sql           sql语句
	 * @param params        传入参数数组
	 * @param types         对应的参数类型数组
	 * @param isOuts        是否为传出参数
	 * @return              传出参数序列
	 * @throws Exception    异常
	 * 2014年5月23日
	 * @author 马宝刚
	 */
	@Override
	public List<Object> c(String sql, Object[] params, int[] types, boolean[] isOuts) throws Exception {
		return call(sql,params,types,isOuts);
	}
	//#endregion

	//#region call 调用存储过程
	/**
	 * 调用存储过程
	 * @param sql           sql语句
	 * @param params        传入参数数组
	 * @param types         对应的参数类型数组
	 * @param isOuts        是否为传出参数
	 * @return              传出参数序列
	 * @throws Exception    异常
	 * 2014年5月23日
	 * @author 马宝刚
	 */
	@Override
	public List<Object> call(String sql, Object[] params, int[] types, boolean[] isOuts) throws Exception {
		//构建返回值
		ArrayList<Object> reList  = new ArrayList<Object>();
		CallableStatement stmt    = null; // 事务
		Connection        conn    = null; // 连接对象
		Integer           timeOut = null; // 查询超时时间（秒）
		try{
			conn = getConn(null); // 获取事务
			stmt = conn.prepareCall(sql);
			//设置条件值
			String paramsLog = DBUtil.fixPreparedStatement(stmt,params,types,isOuts);       // 设置值
			long beforeTime  = System.currentTimeMillis(); // 记录执行开始时间
			// 查询超时时间（秒）
			timeOut = sint(ThreadSession.get("DB_QUERY_TIME_OUT"));
			if(timeOut>0) {
				stmt.setQueryTimeout(timeOut);
			}
			//执行语句
			stmt.execute();
			//执行后设置值
			for (int i=0;i<isOuts.length;i++) {
				if(!isOuts[i]) {
					continue;
				}
				if(types[i]==Types.VARCHAR) {
					reList.add(stmt.getString(i+1));
				}else if(types[i]==Types.INTEGER) {
					reList.add(String.valueOf(stmt.getInt(i+1)));
				}else if(types[i]==Types.DOUBLE) {
					reList.add(String.valueOf(stmt.getDouble(i+1)));
				}else if(types[i]==Types.FLOAT) {
					reList.add(String.valueOf(stmt.getFloat(i+1)));
				}else{
					//获取返回对象
					Object rs = stmt.getObject(i+1);
					if(rs==null) {
						reList.add("");
						continue;
					}
					if(rs instanceof ResultSet) {
						//构建记录集序列
						ArrayList<HashMap<String,Object>> resultSetList = new ArrayList<HashMap<String,Object>>();
						reList.add(resultSetList);
						//获取字段信息
						ResultSetMetaData metaData = null;
						try {
							//调用存储过程后没有返回记录集，此动作会抛异常
							metaData = ((ResultSet)rs).getMetaData();
						}catch(Exception e) {}
						if (metaData!=null) {
							//获取字段数量
							int colCountInt = metaData.getColumnCount();
							boolean hasNext = true; //是否存在下一条记录
							while (hasNext) {
								//构造行记录集容器
								HashMap<String,Object> hasm = new HashMap<String,Object>();
								resultSetList.add(hasm);
								for(int j=0; j<colCountInt; j++) {
									//字段名
									String columnNameStr = (metaData.getColumnLabel(j+1)).toLowerCase();
									if(columnNameStr==null || columnNameStr.length()<1) {
										columnNameStr = (metaData.getColumnName(j+1)).toLowerCase();
									}
									//获取字段值
									Object columnValue = ((ResultSet)rs).getObject(j+1);
									if (columnValue instanceof Clob) {
										hasm.put(columnNameStr,DBUtil.getClobString(((Clob)columnValue)));
									}else if(columnValue instanceof byte[]) {
										//mysql 在语句中使用函数时，有时会将本应该返回字符串的值返回字节数组
										hasm.put(columnNameStr,new String((byte[])columnValue));
									}else {
										columnValue = SString.valueOf(columnValue);
										hasm.put(columnNameStr,columnValue);
									}
								}
								hasNext = ((ResultSet)rs).next();
							}
						}
					}else {
						reList.add(rs);
					}
				}
			}
			log.sqlLog(" DataSource:["+dataSourceName+"] Call Info:+++Result Count[" 
					+ reList.size() + "] Use Time:["+SDate.showMillisecond(System.currentTimeMillis()-beforeTime)+
					"] timeOut:["+timeOut+"] SQL:[\n"+sql+"\n] "+paramsLog,outLog,logFileKey);
			return reList;
		}catch(Exception e){
			e.printStackTrace();
			log.error(" DataSource:["+dataSourceName+"] Call Info:+++Result Count[" 
					+ reList.size() + "] timeOut:["+timeOut+"] SQL:[\n"+sql+"\n] ",e);
			try {
				//执行回滚
				conn.rollback();
			}catch(Exception e2) {}
			throw e;
		}finally{
			try {
				stmt.close();
			} catch (Exception e2) {}
			stmt = null;
			try {
				conn.close();
			} catch (Exception e2) {}
			conn = null;
		}
	}
	//#endregion

	//#region qc 获取查询记录数 全称 queryAllCount
	/**
	 * 获取查询记录数 全称 queryAllCount
	 * 刘虻
	 * 2011-6-2 下午03:10:36
	 * @param qp            分页信息容器
	 * @throws Exception    异常
	 */
	@Override
	public void qc(QueryPageVO qp) throws Exception {
		queryAllCount(qp);
	}
	//#endregion

	//#region fixAllCountSql 通过查询语句拼装出对应的总记录语句
	/**
	 * 通过查询语句拼装出对应的总记录语句
	 * 
	 * 去掉order by 后面的语句。
	 * Oracle数据库，即使不去掉orderby，也能正常获取到记录数，但是发现MsSql会报错
	 * 所以增加方法去掉排序语句段
	 * 
	 * @param sql 查询记录语句
	 * @return    获取查询记录数语句
	 * 2018年8月17日
	 * @author MBG
	 */
	private String fixAllCountSql(String sql) {
		//获取关键字分隔符
		int point = sql.toLowerCase().indexOf("order by");
		if(point>0) {
			sql = sql.substring(0,point);
		}else {
			sql = sql.trim();
			if(sql.endsWith(";")) {
				sql = sql.substring(0,sql.length()-1);
			}
		}
		return  "select count(0) as ct from ("+sql+") ctb";
	}
	//#endregion

	//#region queryAllCount 获取查询记录数
	/**
	 * 获取查询记录数
	 * 刘虻
	 * 2011-6-2 下午03:10:36
	 * @param qp            分页信息容器
	 * @throws Exception    异常
	 */
	@Override
	@SuppressWarnings("unchecked")
	public void queryAllCount(QueryPageVO qp) throws Exception {
		if(qp.sqlObj!=null) {
			//在脚本中采用 <%S   S%> 拼装的信息
			Object[] fixInfos = DBUtil.fixSqlInfo(log,qp.sqlObj); //整理传入值
			qp.sqlObj = null;
			qp.sql = (String)fixInfos[0];
			qp.uList = (List<String>)fixInfos[1];
		}
		if(qp.pageSize<1){
			return;
		}
		long    beforeTime = 0;    // 记录执行开始时间
		String  paramsLog  = null; // 设置条件值
		Integer timeOut    = null; // 查询超时时间（秒）
		if(qp.allCount<1) {
			if(qp.countSql==null || qp.countSql.length()<1) {
				if(qp.sql==null || qp.sql.length()<1) {
					return;
				}
				//如果没有传入获取总数的语句，而且还要做分页查询，一定要拼装获取记录总数的语句
				qp.countSql = fixAllCountSql(qp.sql);
			}
			ResultSet         rs        = null; // 记录集
			PreparedStatement stmt      = null; // 事务
			Connection        conn      = null; // 连接对象
			DBUtil.fixSqlWithPara(qp); //处理查询语句和提交值
			try {
				conn = getConn(null);
				int pType = getPrepareStatementType();
				if(pType==0){
					stmt = conn.prepareStatement(qp.countSql);
				}else{
					stmt = conn.prepareStatement(
							qp.countSql
							,ResultSet.TYPE_SCROLL_INSENSITIVE
							,ResultSet.CONCUR_READ_ONLY);
				}
				if(qp.uParas==null) {
					paramsLog = DBUtil.fixPreparedStatement(stmt,qp.uList); // 设置值
				}else {
					//针对不同的对象,设置不同类型的值
					paramsLog = fixPreparedStatement(stmt,qp.uParas); // 设置值
				}
				beforeTime = System.currentTimeMillis(); //记录执行开始时间

				// 查询超时时间（秒）
				timeOut = sint(ThreadSession.get("DB_QUERY_TIME_OUT"));
				if(timeOut>0) {
					stmt.setQueryTimeout(timeOut);
				}
				// 执行查询
				rs = stmt.executeQuery();
				if (rs.next()) {
					//获取记录集总数
					qp.allCount = rs.getInt(1);
				}
			} catch (Exception e) {
				e.printStackTrace();
				log.error("queryAllCount Exception"+qp,e);
				throw new Exception(e);
			}finally {
				if (rs!=null) {
					try {
						rs.close();
					} catch (Exception e2) {}
					rs = null;
				}
				if (stmt!=null) {
					try {
						stmt.close();
					} catch (Exception e2) {}
					stmt = null;
				}
				if (conn!=null) {
					try {
						conn.close();
					} catch (Exception e2) {}
					conn = null;
				}
			}
		}
		if(qp.pageNo<1){
			qp.pageNo = 1;
		}
		qp.fromId = ((qp.pageNo-1)*qp.pageSize)+1;
		if (qp.fromId<1) {
			qp.fromId = 1;
		}
		qp.toId =  qp.pageNo * qp.pageSize;
		if (qp.pageSize==0) {
			qp.pageCount = 0;
		}else {
			qp.pageCount = qp.allCount / qp.pageSize;
			if (qp.pageSize*qp.pageCount<qp.allCount) {
				qp.pageCount ++;
			}
		}
		log.sqlLog("DataSource:["+dataSourceName+"] allCount:["+qp.allCount+"] pageNo:["+qp.pageNo+"] pageSize:["+qp.pageSize+"] fromId:["
				+qp.fromId+"] toId:["+qp.toId+"] pageCount:["+qp.pageCount+"] Use Time:["+
				SDate.showMillisecond(System.currentTimeMillis()-beforeTime)+"] timeOut:["+timeOut+"] SQL:[\n"+
				qp.countSql+"\n] "+paramsLog,outLog,logFileKey);
	}
	//#endregion

	//#region q 获取查询记录数  全称 queryPage
	/**
	 * 获取查询记录数  全称 queryPage
	 * 刘虻
	 * 2011-6-2 下午03:10:36
	 * @param qp            分页信息容器
	 * @throws Exception    异常
	 */
	@Override
	public void q(QueryPageVO qp) throws Exception {
		queryPage(qp);
	}
	//#endregion

	//#region queryPage 获取查询记录数
	/**
	 * 获取查询记录数
	 * 刘虻
	 * 2011-6-2 下午03:10:36
	 * @param qp            分页信息容器
	 * @throws Exception    异常
	 */
	@Override
	@SuppressWarnings("unchecked")
	public void queryPage(QueryPageVO qp) throws Exception {
		if(qp.sqlObj!=null) {
			//在脚本中采用 <%S   S%> 拼装的信息
			Object[] fixInfos = DBUtil.fixSqlInfo(log,qp.sqlObj); //整理传入值
			qp.sqlObj         = null;
			qp.sql            = (String)fixInfos[0];
			qp.uList          = (List<String>)fixInfos[1];
		}
		if(qp==null || qp.sql==null || qp.sql.length()<1){
			return;
		}
		if(qp.rs.size()>0) {
			qp.rs = new ArrayList<Map<String,String>>();
		}
		DBUtil.fixSqlWithPara(qp); //处理查询语句
		if(qp.pageSize>0 && !qp.noFixPage){
			//处理分页信息
			queryAllCount(qp);
		}
		ResultSet         rs      = null; // 记录集
		PreparedStatement stmt    = null; // 事务
		Connection        conn    = null; // 连接对象
		Integer           timeOut = null; // 查询超时时间（秒）
		try{
			conn = getConn(null);
			//获取事务
			int pType = getPrepareStatementType();
			if(pType==0){
				stmt = conn.prepareStatement(qp.sql);
			}else{
				stmt = 
						conn.prepareStatement(
								qp.sql
								,ResultSet.TYPE_SCROLL_INSENSITIVE
								,ResultSet.CONCUR_READ_ONLY);
			}
			//设置条件值
			String paramsLog = null;
			if(qp.uParas==null) {
				paramsLog = DBUtil.fixPreparedStatement(stmt,qp.uList); // 设置值
			}else {
				//针对不同的对象,设置不同类型的值
				paramsLog = fixPreparedStatement(stmt,qp.uParas); // 设置值
			}
			long beforeTime = System.currentTimeMillis(); //记录执行开始时间
			//查询超时时间（秒）
			timeOut = sint(ThreadSession.get("DB_QUERY_TIME_OUT"));
			if(timeOut>0) {
				stmt.setQueryTimeout(timeOut);
			}
			rs = stmt.executeQuery();// 执行查询
			int rsSize = 0; // 记录集计数器
			ResultSetMetaData metaData = null; //获取字段信息
			try {
				//调用存储过程后没有返回记录集，此动作会抛异常
				metaData = rs.getMetaData();
			}catch(Exception e) {}
			if (metaData!=null) {
				if(qp.fields.size()<1){
					//获取字段数量
					int colCountInt = metaData.getColumnCount();
					String fieldName;
					for(int i=0;i<colCountInt;i++) {
						fieldName = str(metaData.getColumnLabel(i+1)).toLowerCase();
						if(fieldName.length()<1) {
							fieldName = str(metaData.getColumnName(i+1)).toLowerCase();
						}
						qp.fields.add(fieldName);
					}
				}
				boolean loop = false;
				if(qp.fromId>0){
					loop = rs.absolute(qp.fromId); //跳过记录
				}else{
					loop = rs.next();
				}
				//初始化字典类实例
				if(qp.dicts!=null) {
					for(int i=0;i<qp.dicts.length;i++) {
						if(qp.dicts[i] instanceof IDataDict) {
							((IDataDict)qp.dicts[i]).init();
						}
					}
				}
				Object columnValue; //字段值
				while (loop) {
					rsSize++;
					//构造行记录集容器
					HashMap<String,String> hasm = new HashMap<String,String>();
					for (String columnName:qp.fields) {
						//获取字段值
						columnValue = rs.getObject(columnName);
						if (columnValue instanceof Clob) {
							hasm.put(columnName,DBUtil.getClobString(((Clob)columnValue)));
						}else if(columnValue instanceof byte[]) {
							//mysql 在语句中使用函数时，有时会将本应该返回字符串的值返回字节数组
							hasm.put(columnName,new String((byte[])columnValue));
						}else {
							if(columnValue==null){
								columnValue = "";
							}
							hasm.put(columnName,columnValue.toString());
						}
					}
					if(qp.dicts!=null) {
						for(int i=0;i<qp.dicts.length;i++) {
							if(qp.dicts[i] instanceof IDataDict) {
								((IDataDict)qp.dicts[i]).data(hasm);
							}else if(qp.dicts[i] instanceof SListMap) {
								//强制转换为序列容器
								SListMap<Map<String,String>> dict = (SListMap<Map<String,String>>)qp.dicts[i];
								Map<String,String> dMap;
								for(String fEle:dict.keys()) {
									dMap = dict.get(fEle);
									if(dMap==null) {
										continue;
									}
									hasm.put(fEle,dMap.get(hasm.get(fEle)));
								}
							}
						}
					}
					qp.rs.add(hasm);
					if (qp.pageSize>0 && rsSize==qp.pageSize) {
						break;
					}
					loop = rs.next();
				}
			}
			log.sqlLog("DataSource:["+dataSourceName+"] Query: timeOut:["+timeOut+"] pageNo:["+qp.pageNo+"] pageSize:["
					+qp.pageSize+"] fontId:["+qp.fromId+"] qp.toId:["+qp.toId+"] noFixPage:["
					+qp.noFixPage+"]\n Result Count:["+qp.rs.size()+"] Use Time:["+SDate.showMillisecond(System.currentTimeMillis()-beforeTime)+
					"] SQL:[\n"+qp.sql+"\n] \n"+paramsLog,outLog,logFileKey);
			return;
		}catch(Exception e){
			e.printStackTrace();
			log.error("queryList  timeOut:["+timeOut+"] SQL:[\n"+qp.sql+"\n]  Exception "+qp,e);
			try {
				//执行回滚
				conn.rollback();
			}catch(Exception e2) {}
			throw e;
		}finally{
			try {
				rs.close();
			} catch (Exception e2) {}
			rs = null;
			try {
				stmt.close();
			} catch (Exception e2) {}
			stmt = null;
			try {
				conn.close();
			} catch (Exception e2) {}
			conn = null;
		}
	}
	//#endregion

	//#region getDateTime
	/**
	 * 覆盖方法
	 * 刘虻
	 * 2011-6-2 下午03:38:12
	 */
	@Override
	public String getDateTime() {
		return SDate.nowDateTimeString();
	}
	//#endregion

	//#region getTime
	/**
	 * 覆盖方法
	 * 刘虻
	 * 2011-6-2 下午03:38:01
	 */
	@Override
	public String getTime() {
		return SDate.nowTimeString();
	}
	//#endregion

	//#region getDate
	/**
	 * 覆盖方法
	 * 刘虻
	 * 2011-6-2 下午03:37:47
	 */
	@Override
	public String getDate() {
		return SDate.nowDateString();
	}
	//#endregion

	//#region getSID
	/**
	 * 覆盖方法
	 * 刘虻
	 * 2011-6-2 下午03:37:40
	 */
	@Override
	public String getSID() {
		return getSN().getSID();
	}
	//#endregion

	//#region rss
	/**
	 * 覆盖方法
	 * 刘虻
	 * 2011-6-2 下午05:07:32
	 */
	@Override
	public String rss(String fieldPK, int row, List<Map<String,String>> rs) {
		if(rs==null || rs.size()<1) {
			return "";
		}
		if(row<0) {
			row = 0;
		}
		//行记录容器
		Map<String,String> columnMap = rs.get(row);
		if(columnMap==null) {
			return "";
		}
		return SString.valueOf(columnMap.get(fieldPK));
	}
	//#endregion

	//#region frss 获取首行记录指定字段值
	/**
	 * 获取首行记录指定字段值
	 * 刘虻
	 * 2011-6-2 下午05:06:50
	 * @param fieldPK   字段主键
	 * @param rs        记录集
	 * @return          字段值
	 */
	@Override
	public String frss(String fieldPK, List<Map<String,String>> rs) {
		return rss(fieldPK,0,rs);
	}
	//#endregion

	//#region u 更新Blob字段值 全称 updateBlobByPK
	/**
	 * 更新Blob字段值 全称 updateBlobByPK
	 * @param blobSql 更新语句  slect content from table_name where id=? for update
	 * @param pk 主键值
	 * @param fieldName BLob字段名
	 * @param blobIs BLob 字段值读入流
	 * @throws Exception 执行发生异常
	 * 2014年4月10日
	 * @author 马宝刚
	 */
	@Override
	public void u(
			String blobSql
			,String pk
			,String fieldName
			,InputStream blobIs) throws Exception {
		updateBlobByPK(blobSql,pk,fieldName,blobIs);
	}
	//#endregion

	//#region updateBlobByPK 更新Blob字段值
	/**
	 * 更新Blob字段值
	 * @param blobSql 更新语句  slect content from table_name where id=? for update
	 * @param pk 主键值
	 * @param fieldName BLob字段名
	 * @param blobIs BLob 字段值读入流
	 * @throws Exception 执行发生异常
	 * 2014年4月10日
	 * @author 马宝刚
	 */
	@Override
	public void updateBlobByPK(
			String blobSql
			,String pk
			,String fieldName
			,InputStream blobIs) throws Exception {
		//构建提交值
		ArrayList<String> uList = new ArrayList<String>();
		uList.add(pk);
		updateBlob(blobSql,uList,fieldName,blobIs);
	}
	//#endregion

	//#region updateBlob 更新BLob字段
	/**
	 * 更新BLob字段
	 * 
	 * 再此之前需要在insert语句中将BLob字段设置为 empty_blob()函数值
	 * 
	 * @author 刘虻
	 * 2009-9-21下午07:48:59
	 * @param clobSql 更新语句 select content from table_name where id=? for update
	 * @param uList  语句中对应的条件值
	 * @param fieldName BLob字段名
	 * @param fieldValue BLob 字段值
	 * @throws Exception 执行发生异常
	 */
	@Override
	public void updateBlob(
			String blobSql
			,List<String> uList
			,String fieldName
			,InputStream blobIs) throws Exception {
		ResultSet         rs         = null;     // 记录集
		PreparedStatement stmt       = null;     // 事务
		Connection        conn       = null;     // 获取带事务的数据库连接
		Boolean           autoCommit = null;     // 是否原来为自动提交
		String            session    = getSID(); // 会话主键
		Integer           timeOut    = null;     // 查询超时时间（秒）
		try {
			conn = getConn(session); // 数据库连接对象
			autoCommit = new Boolean(conn.getAutoCommit());
			((ConnectionImpl)conn).getKernel().setAutoCommit(false);
			//获取事务
			int pType = getPrepareStatementType();
			if(pType==0){
				stmt = conn.prepareStatement(blobSql);
			}else{
				stmt = conn.prepareStatement(
				  blobSql,
			      ResultSet.TYPE_SCROLL_INSENSITIVE,
				  ResultSet.CONCUR_UPDATABLE);
			}
			//设置条件值?
			String paramsLog = DBUtil.fixPreparedStatement(stmt,uList); // 设置值
			Object time = log.runBefore(); //记录执行开始时间
			//查询超时时间（秒）
			timeOut = sint(ThreadSession.get("DB_QUERY_TIME_OUT"));
			if(timeOut>0) {
				stmt.setQueryTimeout(timeOut);
			}
			// 执行查询
			rs = stmt.executeQuery();
			if(rs.next()) {   
				// 得到java.sql.Blob对象后强制转换为oracle.sql.BLOB   
				Blob blob = rs.getBlob(fieldName);
				if(blob==null) {
					return;
				}
				//反射获取调用方法，否则还得引入class12.jar包
				Method method = blob.getClass().getMethod("getBinaryOutputStream");
				OutputStream outStream = (OutputStream)method.invoke(blob,new Object[] {});
				try {
					//构建写入缓存
					byte[] buffer = new byte[10240];
					int bytesRead = -1;
					while ((bytesRead = blobIs.read(buffer)) != -1) {
						outStream.write(buffer, 0, bytesRead);
					}
					outStream.flush();
				}finally {
					try {
						blobIs.close();
					}catch (IOException ex) {
						ex.printStackTrace();
					}
					try {
						outStream.close();
					}catch (IOException ex) {
						ex.printStackTrace();
					}
				}
			}   
			dataManager.commit(session);
			log.writeRuntime(time,"Deal:[Update BLob] DataSource:["+dataSourceName+"] QueryUpdate:\n"+blobSql+"\n"+paramsLog);
		} catch (Exception e) {
			e.printStackTrace();
			log.error("Deal:[Insert BLob] DataSource:["+dataSourceName+"] BLob Sql:["+blobSql+"]\n",e);
			//执行回滚
			try {
				dataManager.rollback(session);
			}catch(Exception e2) {}
			throw new DBException(this,DebugUtil.getExceptionMessage(e));
		}finally {
			if (rs!=null) {
				try {
					rs.close();
				} catch (Exception e2) {}
				rs = null;
			}
			if (stmt!=null) {
				try {
					stmt.close();
				} catch (Exception e2) {}
				stmt = null;
			}
			if(conn!=null) {
				if(autoCommit!=null) {
					conn.setAutoCommit(autoCommit.booleanValue());
				}
				try {
					conn.close();
				} catch (Exception e2) {}
				conn = null;
				//关闭数据库连接
				dataManager.close(session);
			}
		}
	}
	//#endregion

	//#region updateBlob 更新BLob字段
	/**
	 * 更新BLob字段
	 * @author 刘虻
	 * 2009-9-21下午07:48:59
	 * @param clobSql 更新语句 update content from table_name where id=?
	 * @param pkValue 主键值
	 * @param blobIs  Blob值流
	 * @throws Exception 执行发生异常
	 */
	@Override
	public void updateBlob(
			String blobSql,
			String pkValue,
			InputStream blobIs) throws Exception {
		ResultSet         rs   = null; // 记录集
		PreparedStatement stmt = null; // 事务
		Connection        conn = null; // 获取带事务的数据库连接
		try {
			conn = getConn(null); // 数据库连接对象
			stmt = conn.prepareStatement(blobSql); //获取事务
			Object time = log.runBefore(); //记录执行开始时间
			stmt.setBinaryStream(1,blobIs);
			stmt.setString(2,pkValue);
			stmt.executeUpdate();
			log.writeRuntime(time,"Deal:[Update BLob] DataSource:["+getSourceName()+"] QueryUpdate:\n"+blobSql+"\npkValue:["+pkValue+"]");
		} catch (Exception e) {
			e.printStackTrace();
			log.error("Deal:[Insert BLob] DataSource:["+getSourceName()+"] BLob Sql:[\n"+blobSql+"\n]\n",e);
			//执行回滚
			try {
				conn.rollback();
			}catch(Exception e2) {}
			throw new DBException(this,DebugUtil.getExceptionMessage(e));
		}finally {
			if(rs!=null) {
				try {
					rs.close();
				} catch (Exception e2) {}
				rs = null;
			}
			if(stmt!=null) {
				try {
					stmt.close();
				} catch (Exception e2) {}
				stmt = null;
			}
			if (conn!=null) {
				try {
					conn.close();
				} catch (Exception e2) {}
				conn = null;
			}
			try {
				blobIs.close();
			}catch (IOException ex) {
				ex.printStackTrace();
			}
		}
	}
	//#endregion

	//#region q 获取Blob字段值 读入流
	/**
	 * 获取Blob字段值 读入流
	 * @param sql            取数语句   
	 * 语句中只能有一个blob字段，并且用主键定位 比如  select blobContent from table where id=?
	 * @param pkValue    主键值
	 * @param blobOuter blob字段输出处理类
	 * @throws Exception 异常
	 * 2014年4月11日
	 * @author 马宝刚
	 */
	@Override
	public void q(String sql, String pkValue, IBlobOuter blobOuter) throws Exception {
		queryBlob(sql,pkValue,blobOuter);
	}
	//#endregion

	//#region queryBlob 查询带Blob字段的记录集（只查询符合条件的第一条记录）
	/**
	 * 查询带Blob字段的记录集（只查询符合条件的第一条记录）
	 * 注意：有个特殊的字段值，即 blob字段名__length  标记输出内容大小
	 * @param               提交值信息
	 * @return              记录集 key 主键  value：字段值或者为读入流
	 * @throws Exception  异常
	 * 2017年4月7日
	 * @author 马宝刚
	 */
	@Override
	@SuppressWarnings("unchecked")
	public Map<String,?> queryBlob(Object[] infos) throws Exception {
		Object[] fixInfos = DBUtil.fixSqlInfo(log,infos);
		return queryBlob((String)fixInfos[0],BaseUtil.listToArray((List<String>)fixInfos[1]));
	}
	//#endregion

	//#region queryBlob 查询带Blob字段的记录集（只查询符合条件的第一条记录）
	/**
	 * 查询带Blob字段的记录集（只查询符合条件的第一条记录）
	 * 注意：有个特殊的字段值，即 blob字段名__length  标记输出内容大小
	 * @param sql        查询语句
	 * @param uValueArrl 提交值
	 * @return 记录集 key 主键  value：字段值或者为读入流
	 * @throws Exception 异常
	 * 2017年4月7日
	 * @author MBG
	 */
	@Override
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public Map queryBlob(String sql,Object[] params) throws Exception {
		ResultSet         rs      = null; // 记录集
		PreparedStatement stmt    = null; // 事务
		Connection        conn    = null; // 连接对象
		Integer           timeOut = null; // 查询超时时间（秒）
		try{
			conn         = getConn(null);
			Object[] res = DBUtil.fixSqlWithPara(sql,params); //处理语句中的 (#)关键字
			sql          = str(res[0]);
			params       = (Object[])res[1];
			//获取事务
			int pType = getPrepareStatementType();
			if(pType==0){
				stmt = conn.prepareStatement(sql);
			}else{
				stmt = 
						conn.prepareStatement(
								sql
								,ResultSet.TYPE_SCROLL_INSENSITIVE
								,ResultSet.CONCUR_READ_ONLY);
			}
			//设置条件值
			String paramsLog = fixPreparedStatement(stmt,params); // 设置值;
			long beforeTime  = System.currentTimeMillis(); // 记录执行开始时间
			// 查询超时时间（秒）
			timeOut = sint(ThreadSession.get("DB_QUERY_TIME_OUT"));
			if(timeOut>0) {
				stmt.setQueryTimeout(timeOut);
			}
			rs = stmt.executeQuery();// 执行查询
			ResultSetMetaData metaData = null; //获取字段信息
			//构建返回值
			Map reMap = new HashMap();
			try {
				//调用存储过程后没有返回记录集，此动作会抛异常
				metaData = rs.getMetaData();
			}catch(Exception e) {}
			if (metaData==null || !rs.next()) {
				return reMap;
			}
			String columnName;  // 字段名
			Object columnValue; // 字段值
			for (int i=1;i<=metaData.getColumnCount();i++) {
				columnName = SString.valueOf(metaData.getColumnName(i)).toLowerCase() ;
				if(metaData.getColumnType(i)==Types.BLOB 
						|| metaData.getColumnType(i)==Types.LONGVARBINARY) {
					Blob blob = rs.getBlob(i);
					if(blob!=null) {
						reMap.put(columnName+"_length",String.valueOf(blob.length()));
						reMap.put(columnName,blob.getBinaryStream());
					}
					continue;
				}
				//获取字段值
				columnValue = rs.getObject(i);
				if (columnValue instanceof Clob) {
					reMap.put(columnName,DBUtil.getClobString(((Clob)columnValue)));
				}else if(columnValue instanceof byte[]) {
					//mysql 在语句中使用函数时，有时会将本应该返回字符串的值返回字节数组
					reMap.put(columnName,new String((byte[])columnValue));
				}else {
					if(columnValue==null){
						columnValue = "";
					}
					reMap.put(columnName,columnValue.toString());
				}
			}
			log.sqlLog(" DataSource:["+dataSourceName+"] Query Info: timeOut:["+timeOut+"] Use Time:["+
			  SDate.showMillisecond(System.currentTimeMillis()-beforeTime)+
					"] SQL:[\n"+sql+"\n] "+paramsLog,outLog,logFileKey);
			return reMap;
		}catch(Exception e){
			e.printStackTrace();
			log.error("queryList DataSource:["+dataSourceName+"] timeOut:["+timeOut+"] SQL:["+sql+"] Exception ",e);
			try {
				//执行回滚
				conn.rollback();
			}catch(Exception e2) {}
			throw e;
		}finally{
			try {
				rs.close();
			} catch (Exception e2) {}
			rs = null;
			try {
				stmt.close();
			} catch (Exception e2) {}
			stmt = null;
			try {
				conn.close();
			} catch (Exception e2) {}
			conn = null;
		}
	}
	//#endregion

	//#region queryBlob 获取Blob字段值 读入流
	/**
	 * 获取Blob字段值 读入流
	 * @param sql            取数语句   
	 * 语句中只能有一个blob字段，并且用主键定位 比如  select blobContent from table where id=?
	 * @param pkValue    主键值
	 * @param blobOuter blob字段输出处理类
	 * @throws Exception 异常
	 * 2014年4月11日
	 * @author 马宝刚
	 */
	@Override
	public void queryBlob(String sql, String pkValue, IBlobOuter blobOuter) throws Exception {
		ResultSet         rs      = null; // 记录集
		PreparedStatement stmt    = null; // 事务
		Connection        conn    = null; // 连接对象
		Integer           timeOut = null; // 查询超时时间（秒）
		try{
			conn = getConn(null);
			int pType = getPrepareStatementType(); // 获取事务
			if(pType==0){
				stmt = conn.prepareStatement(sql);
			}else{
				stmt = conn
				  .prepareStatement(
				    sql,
				    ResultSet.TYPE_SCROLL_INSENSITIVE,
				    ResultSet.CONCUR_READ_ONLY);
			}
			//设置条件值
			ArrayList<String> uList = new ArrayList<String>();
			uList.add(pkValue);
			String paraLogs = DBUtil.fixPreparedStatement(stmt,uList);       // 设置值
			long beforeTime = System.currentTimeMillis(); //记录执行开始时间
			//查询超时时间（秒）
			timeOut = sint(ThreadSession.get("DB_QUERY_TIME_OUT"));
			if(timeOut>0) {
				stmt.setQueryTimeout(timeOut);
			}
			rs = stmt.executeQuery(); // 执行查询
			Blob reBlob = null;       // 要返回的Blob字段值对象
			if(!rs.next()) {
				return;
			}
			reBlob = rs.getBlob(1);
			if(blobOuter!=null && reBlob!=null) {
				blobOuter.outer(reBlob.getBinaryStream());
			}
			log.sqlLog("DataSource:["+dataSourceName+"] queryBlob Use Time:[" + 
			  SDate.showMillisecond(System.currentTimeMillis()-beforeTime)+
					"] timeOut:["+timeOut+"] SQL:[\n"+sql+"\n] "+paraLogs,outLog,logFileKey);
		}catch(Exception e){
			e.printStackTrace();
			log.error("queryBlob Exception DataSource:["+dataSourceName+"] timeOut:["+timeOut+"] Sql:[\n"+sql+
					"\n] pkValue:["+pkValue+"] blobOuter:["+blobOuter+"]",e);
			try {
				conn.rollback(); // 执行回滚
			}catch(Exception e2) {}
			throw e;
		}finally{
			try {
				rs.close();
			} catch (Exception e2) {}
			rs = null;
			try {
				stmt.close();
			} catch (Exception e2) {}
			stmt = null;
			try {
				conn.close();
			} catch (Exception e2) {}
			conn = null;
		}
	}
	//#endregion

	//#region updateClob 更新CLob字段  警告：改方法只针对Oracle操蛋数据库
	/**
	 * 更新CLob字段  警告：改方法只针对Oracle操蛋数据库
	 * 
	 * 再此之前需要在insert语句中将CLob字段设置为 empty_clob()函数值
	 * 
	 * @author 刘虻
	 * 2009-9-21下午07:48:59
	 * @param clobSql 更新语句  slect content from table_name where id=? for update
	 * @param uList 设置Clob条件值对象
	 * @param fieldName CLob字段名
	 * @param fieldValue CLob 字段值
	 * @throws Exception 执行发生异常
	 */
	@Override
	public void updateClob(
			String clobSql
			,List<String> uList
			,String fieldName
			,String fieldValue) throws Exception {
		ResultSet         rs         = null;     // 记录集
		PreparedStatement stmt       = null;     // 事务
		Connection        conn       = null;     // 获取带事务的数据库连接
		Boolean           autoCommit = null;     // 是否原来为自动提交
		String            session    = getSID(); // 会话主键
		Integer           timeOut    = null;     // 查询超时时间（秒）
		try {
			conn       = getConn(session); // 数据库连接对象
			autoCommit = new Boolean(conn.getAutoCommit());
			((ConnectionImpl)conn).getKernel().setAutoCommit(false);
			//获取事务
			int pType = getPrepareStatementType();
			if(pType==0){
				stmt = conn.prepareStatement(clobSql);
			}else{
				stmt = 
						conn
						.prepareStatement(
								clobSql
								,ResultSet.TYPE_SCROLL_INSENSITIVE
								,ResultSet.CONCUR_UPDATABLE);
			}
			//设置条件值?
			String paramsLog = DBUtil.fixPreparedStatement(stmt,uList); // 设置值
			Object time      = log.runBefore(); //记录执行开始时间
			// 查询超时时间（秒）
			timeOut = sint(ThreadSession.get("DB_QUERY_TIME_OUT"));
			if(timeOut>0) {
				stmt.setQueryTimeout(timeOut);
			}
			// 执行查询
			rs = stmt.executeQuery();
			if (rs.next()) {   
				// 得到java.sql.Clob对象后强制转换为oracle.sql.CLOB   
				Clob clob = rs.getClob(fieldName);
				//反射获取调用方法，否则还得引入class12.jar包
				Method method = clob.getClass().getMethod("getCharacterOutputStream");
				Writer outStream = (Writer)method.invoke(clob,new Object[] {});
				// data是传入的字符串，定义：String data   
				char[] charArray = fieldValue.toCharArray();   
				outStream.write(charArray, 0, charArray.length);   
				outStream.flush();   
				outStream.close();   
			}   
			dataManager.commit(session);
			log.writeRuntime(time,"Deal:[Update CLob] DataSource:["+dataSourceName+"] Begin QueryUpdate:\n"+clobSql+"\n"+paramsLog);
		} catch (Exception e) {
			e.printStackTrace();
			log.error("Deal:[Insert CLob] DataSource:["+dataSourceName+"] CLob Sql:[\n"+clobSql+"\n]\n",e);
			//执行回滚
			try {
				dataManager.rollback(session);
			}catch(Exception e2) {}
			throw new DBException(this,DebugUtil.getExceptionMessage(e));
		}finally {
			if (rs!=null) {
				try {
					rs.close();
				} catch (Exception e2) {}
				rs = null;
			}
			if (stmt!=null) {
				try {
					stmt.close();
				} catch (Exception e2) {}
				stmt = null;
			}
			if (conn!=null) {
				if(autoCommit!=null) {
					conn.setAutoCommit(autoCommit.booleanValue());
				}
				try {
					conn.close();
				} catch (Exception e2) {}
				conn = null;
			}
		}
	}
	//#endregion

	//#region getConn 获取数据库链接
	/**
	 * 获取数据库链接
	 * @return 数据库链接对象
	 * @throws Exception 异常
	 * 2015年11月23日
	 * @author 马宝刚
	 */
	@Override
	public Connection getConn() throws Exception {
		return getConn(null);
	}
	//#endregion

	//#region getConn 获取数据库链接
	/**
	 * 获取数据库链接
	 * @param sessionKey        会话主键（事务处理）
	 * @return 数据库链接对象
	 * @throws Exception 异常
	 * 2015年11月23日
	 * @author 马宝刚
	 */
	@Override
	@SuppressWarnings("unchecked")
	public Connection getConn(String sessionKey) throws Exception {
		if(sessionKey==null) {
			List<String> keyList = (List<String>)ThreadSession.get("_db_transaction_");
			if(keyList!=null && keyList.size()>0) {
				sessionKey = keyList.get(0);
			}
		}
		if(sessionKey==null) {
			return dataManager.getConnection(dataSourceName,sessionKey,true); // 数据库连接对象（自动提交数据）
		}
		return dataManager.getConnection(dataSourceName,sessionKey,false); // 数据库连接对象（事务处理）
	}
	//#endregion

	//#region getConnNoSession (该方法已废弃)
	/**
	 * (该方法已废弃)，因为如果一个过程启用了事务，在新增数据后查询刚才新增的数据
	 * 查询用的数据库链接是另外的数据库链接，那么无法查询到刚才插入的数据，导致报错
	 * 获取数据库链接（如果sessionKey为空时，无事物处理，通常用来查询）
	 * @param sessionKey  数据库会话主键
	 * @return            数据库连接类实例
	 * @throws Exception  异常
	 * 2019年5月14日
	 * @author MBG
	 */
	//  private Connection getConnNoSession(String sessionKey) throws Exception {
	//    if(sessionKey==null) {
	//      return dataManager.getConnection(dataSourceName,sessionKey,true); // 数据库连接对象（自动提交数据）
	//    }
	//    return dataManager.getConnection(dataSourceName,sessionKey,false); // 数据库连接对象（事务处理）
	//  }
	//#endregion

	//#region getDataManager 获取数据库连接池管理类
	/**
	 * 获取数据库连接池管理类
	 * @return 数据库连接池管理类
	 * 2015年11月23日
	 * @author 马宝刚
	 */
	@Override
	public IDataManager getDataManager() {
		return dataManager;
	}
	//#endregion

	//#region dm 获取数据库连接池管理类
	/**
	 * 获取数据库连接池管理类
	 * @return 数据库连接池管理类
	 * 2015年11月23日
	 * @author 马宝刚
	 */
	@Override
	public IDataManager dm() {
		return dataManager;
	}
	//#endregion

	//#region queryString 将查询出的记录集采用这种方式输出为字符串 
	/**
	 * 将查询出的记录集采用这种方式输出为字符串 
	 *  row1_col1|row1_col2|row1_col3,row2_col1|row2_col2|row2_col3
	 *  即字段值之间用|分割，行数据之间用半角逗号分割
	 * @param sql         查询语句
	 * @param params      提交值数组
	 * @param value       是否只取一条记录
	 * @return 记录集字符串（用逗号分割）
	 * @throws Exception 异常
	 * 2016年10月2日
	 * @author MBG
	 */
	@Override
	public String queryString(
			String sql, Object[] params,boolean onlyOne) throws Exception {
		return queryString(sql,params,onlyOne,null);
	}
	//#endregion

	//#region queryString 将查询出的记录集采用这种方式输出为字符串 
	/**
	 * 将查询出的记录集采用这种方式输出为字符串 
	 *  row1_col1|row1_col2|row1_col3,row2_col1|row2_col2|row2_col3
	 *  即字段值之间用|分割，行数据之间用半角逗号分割
	 * @param sql         查询语句
	 * @param params      提交值数组
	 * @param value       是否只取一条记录
	 * @param splitStr    如果返回多条记录，分隔符值（为空时为半角逗号）
	 * @return 记录集字符串（用逗号分割）
	 * @throws Exception 异常
	 * 2016年10月2日
	 * @author MBG
	 */
	@Override
	public String queryString(
			String sql, Object[] params,boolean onlyOne,String splitStr) throws Exception {
		ResultSet         rs      = null; // 记录集
		PreparedStatement stmt    = null; // 事务
		Connection        conn    = null; // 连接对象
		Integer           timeOut = null; // 查询超时时间（秒）
		if(!onlyOne && (splitStr==null || splitStr.length()<1)) {
			splitStr = ",";
		}
		try{
			conn = getConn(null);
			Object[] res = DBUtil.fixSqlWithPara(sql,params); //处理语句中的 (#)关键字
			sql = str(res[0]);
			params = (Object[])res[1];
			//获取事务
			int pType = getPrepareStatementType();
			if(pType==0){
				stmt = conn.prepareStatement(sql);
			}else{
				stmt = 
						conn.prepareStatement(
								sql
								,ResultSet.TYPE_SCROLL_INSENSITIVE
								,ResultSet.CONCUR_READ_ONLY);
			}
			//设置条件值
			String paramsLog  = fixPreparedStatement(stmt,params); // 设置值
			long   beforeTime = System.currentTimeMillis();        // 记录执行开始时间
			// 查询超时时间（秒）
			timeOut = sint(ThreadSession.get("DB_QUERY_TIME_OUT"));
			if(timeOut>0) {
				stmt.setQueryTimeout(timeOut);
			}
			rs = stmt.executeQuery();        // 执行查询
			int columnCount = rs.getMetaData().getColumnCount(); //共多少列
			//构造返回值
			StringBuffer reSbf = new StringBuffer();
			StringBuffer rowSbf; //行字符串
			Object columnValue; //字段值
			//记录数
			int rsCount = 0;
			while (rs.next()) {
				rowSbf = new StringBuffer();
				rsCount++;
				if(rsCount>1) {
					reSbf.append(splitStr);
				}
				for(int i=1;i<=columnCount;i++) {
					if(rowSbf.length()>0) {
						rowSbf.append("|");
					}
					//获取字段值
					columnValue = rs.getObject(1);
					if (columnValue instanceof Clob) {
						rowSbf.append(DBUtil.getClobString(((Clob)columnValue)));
					}else if(columnValue instanceof byte[]) {
						//mysql 在语句中使用函数时，有时会将本应该返回字符串的值返回字节数组
						rowSbf.append(new String((byte[])columnValue));
					}else {
						if(columnValue==null){
							columnValue = "";
						}
						rowSbf.append(columnValue);
					}
				}
				reSbf.append(rowSbf);
				if(onlyOne) {
					break;
				}
			}
			log.sqlLog(" DataSource:["+dataSourceName+"] Query Info:+++Result Count["+rsCount+"] timeOut:["+timeOut+"] Use Time:["
					+SDate.showMillisecond(System.currentTimeMillis()-beforeTime)+"] SQL:["+sql+"] "+paramsLog,outLog,logFileKey);
			return reSbf.toString();
		}catch(Exception e){
			e.printStackTrace();
			log.error("queryList Exception DataSource:["+dataSourceName+"] Sql:[\n"+sql+"\n] uList:["+DebugUtil.getArrayString(params)+"]",e);
			try {
				//执行回滚
				conn.rollback();
			}catch(Exception e2) {}
			throw e;
		}finally{
			try {
				rs.close();
			} catch (Exception e2) {}
			rs = null;
			try {
				stmt.close();
			} catch (Exception e2) {}
			stmt = null;
			try {
				conn.close();
			} catch (Exception e2) {}
			conn = null;
		}
	}
	//#endregion

	//#region queryMap 简称 qm
	/**
	 * 简称 qm
	 * 仅允许查两个字段值的记录，第一个字段值作为Map的key，第二个断指作为Map的Value
	 * @param infos 查询传入信息
	 * @return      返回数据 key第一个字段值  value第二个字段值
	 * @throws Exception 异常
	 * 2017年9月11日
	 * @author MBG
	 */
	@Override
	public Map<String,String> queryMap(Object[] infos) throws Exception {
		return qm(infos);
	}
	//#endregion

	//#region qm 全称 queryMap
	/**
	 * 全称 queryMap
	 * 仅允许查两个字段值的记录，第一个字段值作为Map的key，第二个断指作为Map的Value
	 * @param infos 查询传入信息
	 * @return      返回数据 key第一个字段值  value第二个字段值
	 * @throws Exception 异常
	 * 2017年9月11日
	 * @author MBG
	 */
	@Override
	@SuppressWarnings("unchecked")
	public Map<String,String> qm(Object[] infos) throws Exception {
		Object[] fixInfos      = DBUtil.fixSqlInfo(log,infos); // 整理传入值
		ResultSet rs           = null;              // 记录集
		PreparedStatement stmt = null;              // 事务
		Connection conn        = null;              // 连接对象
		String sql             = null;              // 处理后的查询语句
		Integer timeOut        = null;              // 查询超时时间（秒）
		try{
			conn = getConn(null);
			sql = DBUtil.fixSqlWithPara((String)fixInfos[0],(List<String>)fixInfos[1]); //处理语句中的 (#)关键字
			//获取事务
			int pType = getPrepareStatementType();
			if(pType==0){
				stmt = conn.prepareStatement(sql);
			}else{
				stmt = 
						conn.prepareStatement(
								sql
								,ResultSet.TYPE_SCROLL_INSENSITIVE
								,ResultSet.CONCUR_READ_ONLY);
			}
			//设置条件值
			String paramsLog = DBUtil.fixPreparedStatement(stmt,(List<String>)fixInfos[1]);    // 设置值
			// 构造返回值
			Map<String,String> reMap = new HashMap<String,String>();
			long beforeTime = System.currentTimeMillis(); //记录执行开始时间
			// 查询超时时间（秒）
			timeOut = sint(ThreadSession.get("DB_QUERY_TIME_OUT"));
			if(timeOut>0) {
				stmt.setQueryTimeout(timeOut);
			}
			rs = stmt.executeQuery();        //执行查询
			ResultSetMetaData metaData = null;    //获取字段信息
			try {
				//调用存储过程后没有返回记录集，此动作会抛异常
				metaData = rs.getMetaData();
			}catch(Exception e) {}
			if (metaData!=null) {
				//获取字段数量
				if(metaData.getColumnCount()<2) {
					throw new Exception("DataSource:["+dataSourceName+"] QueryMap Sql:[\n"+sql+"\n] need Two Fields Value");
				}
				Object key;    //返回容器主键
				Object value;  //返回容器值
				while (rs.next()) {
					key   = rs.getObject(1);
					if(key instanceof Clob) {
						key = DBUtil.getClobString(((Clob)key));
					}else if(key instanceof byte[]) {
						//mysql 在语句中使用函数时，有时会将本应该返回字符串的值返回字节数组
						key = new String((byte[])key);
					}else if(key==null){
						key = "";
					}
					value = rs.getObject(2);
					if(value instanceof Clob) {
						value = DBUtil.getClobString(((Clob)value));
					}else if(value instanceof byte[]) {
						//mysql 在语句中使用函数时，有时会将本应该返回字符串的值返回字节数组
						value = new String((byte[])value);
					}else if(value==null){
						value = "";
					}
					reMap.put(SString.valueOf(key),SString.valueOf(value));
				}
			}
			log.sqlLog("DataSource:["+dataSourceName+"] QueryMap Info:+++Result Count[" + reMap.size() + "] timeOut:["+timeOut+"] Use Time:["
					+SDate.showMillisecond(System.currentTimeMillis()-beforeTime)+"] SQL:[\n"+sql+"\n] "+paramsLog,outLog,logFileKey);
			return reMap;
		}catch(Exception e){
			e.printStackTrace();
			log.error("QueryMap Exception DataSource:["+dataSourceName+"] Sql:[\n"+sql+"\n] uList:["+DebugUtil.getListValue((List<String>)fixInfos[1]," ")+"]",e);
			try {
				//执行回滚
				conn.rollback();
			}catch(Exception e2) {}
			throw e;
		}finally{
			try {
				rs.close();
			} catch (Exception e2) {}
			rs = null;
			try {
				stmt.close();
			} catch (Exception e2) {}
			stmt = null;
			try {
				conn.close();
			} catch (Exception e2) {}
			conn = null;
		}
	}
	//#endregion

	//#region queryList 简称：ql
	/**
	 * 简称：ql
	 * 仅允许查一个字段值的记录，作为序列元素返回
	 * @param infos 查询传入信息
	 * @return      返回数据 ele元素：第一个字段值
	 * @throws Exception 异常
	 * 2017年9月11日
	 * @author MBG
	 */
	@Override
	public List<String> queryList(Object[] infos) throws Exception {
		return ql(infos);
	}
	//#endregion

	//#region ql(sql) 仅允许查一个字段值的记录，作为序列元素返回
	/**
	 * 仅允许查一个字段值的记录，作为序列元素返回
	 * @param sql         查询语句
	 * @return            返回数据 ele元素：第一个字段值
	 * @throws Exception  异常
	 * 2024年8月14日
	 * @author MBG
	 */
	public List<String> ql(String sql) throws Exception {
		return ql(new Object[] {sql});
	}
	//#endregion
	
	//#region ql 全称：queryList
	/**
	 * 全称：queryList
	 * 仅允许查一个字段值的记录，作为序列元素返回
	 * @param infos 查询传入信息
	 * @return      返回数据 ele元素：第一个字段值
	 * @throws Exception 异常
	 * 2017年9月11日
	 * @author MBG
	 */
	@Override
	public List<String> ql(String sql,Object[] uValueArrl) throws Exception {
		ResultSet rs           = null;                    // 记录集
		PreparedStatement stmt = null;                    // 事务
		Connection conn        = null;                    // 连接对象
		List<String> reList    = new ArrayList<String>(); // 构造返回值
		List<String> uParas    = new ArrayList<String>(); // 提交值序列
		Integer      timeOut   = null;                    // 查询超时时间（秒）
		try{
			conn = getConn(null);
			//获取事务
			int pType = getPrepareStatementType();
			if(pType==0){
				stmt = conn.prepareStatement(sql);
			}else{
				stmt = 
						conn.prepareStatement(
								sql
								,ResultSet.TYPE_SCROLL_INSENSITIVE
								,ResultSet.CONCUR_READ_ONLY);
			}
			if(uValueArrl!=null) {
				for(int i=0;i<uValueArrl.length;i++) {
					uParas.add(uValueArrl[i]==null?null:uValueArrl[i].toString());
				}
			}
			//设置条件值
			String paramsLog = DBUtil.fixPreparedStatement(stmt,uParas);    // 设置值
			long beforeTime  = System.currentTimeMillis(); //记录执行开始时间
			// 查询超时时间（秒）
			timeOut = sint(ThreadSession.get("DB_QUERY_TIME_OUT"));
			if(timeOut>0) {
				stmt.setQueryTimeout(timeOut);
			}
			rs = stmt.executeQuery();        //执行查询
			ResultSetMetaData metaData = null;    //获取字段信息
			try {
				//调用存储过程后没有返回记录集，此动作会抛异常
				metaData = rs.getMetaData();
			}catch(Exception e) {}
			if (metaData!=null) {
				//获取字段数量
				if(metaData.getColumnCount()<1) {
					throw new Exception("DataSource:["+dataSourceName+"] queryList Sql:[\n"+sql+"\n] need One Fields Value");
				}
				Object ele;    //返回序列元素
				while (rs.next()) {
					ele = rs.getObject(1);
					if(ele instanceof Clob) {
						ele = DBUtil.getClobString(((Clob)ele));
					}else if(ele instanceof byte[]) {
						//mysql 在语句中使用函数时，有时会将本应该返回字符串的值返回字节数组
						ele = new String((byte[])ele);
					}else if(ele==null){
						ele = "";
					}
					reList.add(SString.valueOf(ele));
				}
			}
			log.sqlLog("DataSource:["+dataSourceName+"] queryList Info:+++Result Count[" 
					+ reList.size() + "] timeOut:["+timeOut+"] Use Time ["+SDate.showMillisecond(System.currentTimeMillis()-beforeTime)+
					"] SQL:[\n"+sql+"\n] "+paramsLog,outLog,logFileKey);
			return reList;
		}catch(Exception e){
			e.printStackTrace();
			log.error("queryList Exception DataSource:["+dataSourceName+"] Sql:[\n"+sql+"\n] uList:["+DebugUtil.getListValue(uParas," ")+"]",e);
			try {
				//执行回滚
				conn.rollback();
			}catch(Exception e2) {}
			throw e;
		}finally{
			try {
				rs.close();
			} catch (Exception e2) {}
			rs = null;
			try {
				stmt.close();
			} catch (Exception e2) {}
			stmt = null;
			try {
				conn.close();
			} catch (Exception e2) {}
			conn = null;
		}
	}
	//#endregion

	//#region ql 全称：queryList
	/**
	 * 全称：queryList
	 * 仅允许查一个字段值的记录，作为序列元素返回
	 * @param infos 查询传入信息
	 * @return      返回数据 ele元素：第一个字段值
	 * @throws Exception 异常
	 * 2017年9月11日
	 * @author MBG
	 */
	@Override
	@SuppressWarnings("unchecked")
	public List<String> ql(Object[] infos) throws Exception {
		Object[] fixInfos      = DBUtil.fixSqlInfo(log,infos);  // 整理传入值
		ResultSet rs           = null;               // 记录集
		PreparedStatement stmt = null;               // 事务
		Connection conn        = null;               // 连接对象
		String sql             = null;               // 查询语句
		Integer timeOut        = null;               // 查询超时时间（秒）
		try{
			conn = getConn(null);
			sql = DBUtil.fixSqlWithPara((String)fixInfos[0],(List<String>)fixInfos[1]); //处理语句中的 (#)关键字
			//获取事务
			int pType = getPrepareStatementType();
			if(pType==0){
				stmt = conn.prepareStatement(sql);
			}else{
				stmt = 
						conn.prepareStatement(
								sql
								,ResultSet.TYPE_SCROLL_INSENSITIVE
								,ResultSet.CONCUR_READ_ONLY);
			}
			//设置条件值
			String paramsLog = DBUtil.fixPreparedStatement(stmt,(List<String>)fixInfos[1]);    // 设置值
			// 构造返回值
			List<String> reList = new ArrayList<String>();
			long beforeTime = System.currentTimeMillis(); //记录执行开始时间
			// 查询超时时间（秒）
			timeOut = sint(ThreadSession.get("DB_QUERY_TIME_OUT"));
			if(timeOut>0) {
				stmt.setQueryTimeout(timeOut);
			}
			rs = stmt.executeQuery();        //执行查询
			ResultSetMetaData metaData = null;    //获取字段信息
			try {
				//调用存储过程后没有返回记录集，此动作会抛异常
				metaData = rs.getMetaData();
			}catch(Exception e) {}
			if (metaData!=null) {
				//获取字段数量
				if(metaData.getColumnCount()<1) {
					throw new Exception("DataSource:["+dataSourceName+"] queryList Sql:[\n"+sql+"\n] need One Fields Value");
				}
				Object ele;    //返回序列元素
				while (rs.next()) {
					ele = rs.getObject(1);
					if(ele instanceof Clob) {
						ele = DBUtil.getClobString(((Clob)ele));
					}else if(ele instanceof byte[]) {
						//mysql 在语句中使用函数时，有时会将本应该返回字符串的值返回字节数组
						ele = new String((byte[])ele);
					}else if(ele==null){
						ele = "";
					}
					reList.add(SString.valueOf(ele));
				}
			}
			log.sqlLog("DataSource:["+dataSourceName+"] queryList Info:+++Result Count[" 
					+ reList.size() + "] timeOut:["+timeOut+"] Use Time:["+
					SDate.showMillisecond(System.currentTimeMillis()-beforeTime)+"] SQL:[\n"+sql+"\n] "+paramsLog,outLog,logFileKey);
			return reList;
		}catch(Exception e){
			e.printStackTrace();
			log.error("queryList Exception DataSource:["+dataSourceName+"] Sql:[\n"+sql+"\n] uList:["+DebugUtil.getListValue((List<String>)fixInfos[1]," ")+"]",e);
			try {
				//执行回滚
				conn.rollback();
			}catch(Exception e2) {}
			throw e;
		}finally{
			try {
				rs.close();
			} catch (Exception e2) {}
			rs = null;
			try {
				stmt.close();
			} catch (Exception e2) {}
			stmt = null;
			try {
				conn.close();
			} catch (Exception e2) {}
			conn = null;
		}
	}
	//#endregion

	//#region queryIndex 全称 queryIndex
	/**
	 * 全称 queryIndex
	 * 查询记录集，并按照指定字段值作为返回的key值放入返回容器中
	 * @param indexKey     key值字段名
	 * @param infos        查询提交值
	 * @return             key 指定字段值，value，行记录集
	 * @throws Exception   异常
	 * 2017年9月11日
	 * @author MBG
	 */
	@Override
	public Map<String,Map<String,String>> queryIndex(String indexKey, Object[] infos) throws Exception {
		return qi(indexKey,infos,null);
	}
	//#endregion

	//#region queryIndex 
	/**
	 * 全称 queryIndex
	 * 查询记录集，并按照指定字段值作为返回的key值放入返回容器中
	 * @param indexKey     key值字段名
	 * @param infos        查询提交值
	 * @param dicts        字典类对象数组
	 * @return             key 指定字段值，value，行记录集
	 * @throws Exception   异常
	 * 2017年9月11日
	 * @author MBG
	 */
	@Override
	public Map<String,Map<String,String>> queryIndex(String indexKey, Object[] infos, Object[] dicts) throws Exception {
		return qi(indexKey,infos,dicts);
	}
	//#endregion

	//#region qi 全称 queryIndex
	/**
	 * 全称 queryIndex
	 * 查询记录集，并按照指定字段值作为返回的key值放入返回容器中
	 * @param indexKey     key值字段名
	 * @param infos        查询提交值
	 * @return             key 指定字段值，value，行记录集
	 * @throws Exception   异常
	 * 2017年9月11日
	 * @author MBG
	 */
	@Override
	public Map<String,Map<String,String>> qi(String indexKey, Object[] infos) throws Exception {
		return qi(indexKey,infos,null);
	}
	//#endregion

	//#region qi 全称 queryIndex
	/**
	 * 全称 queryIndex
	 * 查询记录集，并按照指定字段值作为返回的key值放入返回容器中
	 * @param indexKey     key值字段名
	 * @param infos        查询提交值
	 * @param dicts        字典类对象数组
	 * @return             key 指定字段值，value，行记录集
	 * @throws Exception   异常
	 * 2017年9月11日
	 * @author MBG
	 */
	@Override
	@SuppressWarnings("unchecked")
	public Map<String,Map<String,String>> qi(String indexKey,Object[] infos,Object[] dicts) throws Exception {
		Object[] fixInfos      = DBUtil.fixSqlInfo(log,infos); // 整理传入值
		ResultSet rs           = null;              // 记录集
		PreparedStatement stmt = null;              // 事务
		Connection conn        = null;              // 连接对象
		String sql             = null;              // 查询语句
		Object columnValue     = null;              // 字段值
		Integer timeOut        = null;              // 查询超时时间（秒）
		//构建返回值
		Map<String,Map<String,String>> reMap = new HashMap<String,Map<String,String>>();
		if(indexKey==null || indexKey.length()<1) {
			return reMap;
		}
		try{
			conn = getConn(null);
			sql = DBUtil.fixSqlWithPara((String)fixInfos[0],(List<String>)fixInfos[1]); //处理语句中的 (#)关键字
			//获取事务
			int pType = getPrepareStatementType();
			if(pType==0){
				stmt = conn.prepareStatement(sql);
			}else{
				stmt = 
						conn.prepareStatement(
								sql
								,ResultSet.TYPE_SCROLL_INSENSITIVE
								,ResultSet.CONCUR_READ_ONLY);
			}
			//设置条件值
			String paramsLog = DBUtil.fixPreparedStatement(stmt,(List<String>)fixInfos[1]);// 设置值
			long beforeTime  = System.currentTimeMillis(); // 记录执行开始时间
			// 查询超时时间（秒）
			timeOut = sint(ThreadSession.get("DB_QUERY_TIME_OUT"));
			if(timeOut>0) {
				stmt.setQueryTimeout(timeOut);
			}
			rs = stmt.executeQuery();        // 执行查询
			ResultSetMetaData metaData = null;    //获取字段信息
			try {
				//调用存储过程后没有返回记录集，此动作会抛异常
				metaData = rs.getMetaData();
			}catch(Exception e) {}
			if (metaData!=null) {
				//获取字段数量
				int colCountInt = metaData.getColumnCount();
				//字段名数组
				String[] fieldNames = new String[colCountInt];
				for(int i=0;i<colCountInt;i++) {
					fieldNames[i] = str(metaData.getColumnLabel(i+1)).toLowerCase();
					if(fieldNames[i].length()<1) {
						fieldNames[i] = str(metaData.getColumnName(i+1)).toLowerCase();
					}
				}
				//初始化字典类实例
				if(dicts!=null) {
					for(int i=0;i<dicts.length;i++) {
						if(dicts[i] instanceof IDataDict) {
							((IDataDict)dicts[i]).init();
						}
					}
				}
				HashMap<String,String> hasm; //行记录集容器
				while (rs.next()) {
					//构造行记录集容器
					hasm = new HashMap<String,String>();
					for (int i=0; i<colCountInt; i++) {
						//获取字段值
						columnValue = rs.getObject(fieldNames[i]);
						if (columnValue instanceof Clob) {
							hasm.put(fieldNames[i],DBUtil.getClobString(((Clob)columnValue)));
						}else if(columnValue instanceof byte[]) {
							//mysql 在语句中使用函数时，有时会将本应该返回字符串的值返回字节数组
							hasm.put(fieldNames[i],new String((byte[])columnValue));
						}else {
							if(columnValue==null){
								columnValue = "";
							}
							hasm.put(fieldNames[i],columnValue.toString());
						}
					}
					if(dicts!=null) {
						for(int i=0;i<dicts.length;i++) {
							if(dicts[i] instanceof IDataDict) {
								((IDataDict)dicts[i]).data(hasm);
							}else if(dicts[i] instanceof SListMap) {
								//强制转换为序列容器
								SListMap<Map<String,String>> dict = (SListMap<Map<String,String>>)dicts[i];
								Map<String,String> dMap;
								for(String fEle:dict.keys()) {
									dMap = dict.get(fEle);
									if(dMap==null) {
										continue;
									}
									hasm.put(fEle,dMap.get(hasm.get(fEle)));
								}
							}  
						}
					}
					reMap.put(hasm.get(indexKey),hasm);
				}
			}
			log.sqlLog("DataSource:["+dataSourceName+"] QueryIndex Info:+++Result Count[" 
					+ reMap.size() + "] timeOut:["+timeOut+"] Use Time:["+SDate.showMillisecond(System.currentTimeMillis()-beforeTime)+
					"] SQL:[\n"+sql+"\n] "+paramsLog,outLog,logFileKey);
			return reMap;
		}catch(Exception e){
			e.printStackTrace();
			log.error("QueryIndex Exception DataSource:["+dataSourceName+"] Sql:[\n"+sql+"\n] uList:["+DebugUtil.getListValue((List<String>)fixInfos[1]," ")+"] dicts:["+dicts+"]",e);
			try {
				//执行回滚
				conn.rollback();
			}catch(Exception e2) {}
			throw e;
		}finally{
			try {
				rs.close();
			} catch (Exception e2) {}
			rs = null;
			try {
				stmt.close();
			} catch (Exception e2) {}
			stmt = null;
			try {
				conn.close();
			} catch (Exception e2) {}
			conn = null;
		}
	}
	//#endregion

	//#region queryString 简称：qs
	/**
	 * 简称：qs
	 * 将查询出的记录集采用这种方式输出为字符串 
	 *  row1_col1|row1_col2|row1_col3,row2_col1|row2_col2|row2_col3
	 *  即字段值之间用|分割，行数据之间用半角逗号分割
	 * @param sql         查询语句
	 * @param uValueArrl   提交值数组
	 * @return 记录集字符串（用逗号分割）
	 * @throws Exception 异常
	 * 2016年10月2日
	 * @author MBG
	 */
	@Override
	public String queryString(String sql, Object[] uValueArrl) throws Exception {
		return queryString(sql,uValueArrl,false,null);
	}
	//#endregion

	//#region qs 全称：queryString
	/**
	 * 全称：queryString
	 * 将查询出的记录集采用这种方式输出为字符串 
	 *  row1_col1|row1_col2|row1_col3,row2_col1|row2_col2|row2_col3
	 *  即字段值之间用|分割，行数据之间用半角逗号分割
	 * @param sql         查询语句
	 * @param uValueArrl   提交值数组
	 * @return 记录集字符串（用逗号分割）
	 * @throws Exception 异常
	 * 2016年10月2日
	 * @author MBG
	 */
	@Override
	public String qs(String sql, Object[] uValueArrl) throws Exception {
		return queryString(sql,uValueArrl,false,null);
	}
	//#endregion

	//#region qs 全称：queryString
	/**
	 * 全称：queryString
	 * 将查询出的记录集采用这种方式输出为字符串 
	 *  row1_col1|row1_col2|row1_col3,row2_col1|row2_col2|row2_col3
	 *  即字段值之间用|分割，行数据之间用半角逗号分割
	 * @param sql         查询语句
	 * @param uValueArrl   提交值数组
	 * @param splitStr    分隔符（为空时为半角逗号）
	 * @return 记录集字符串（用逗号分割）
	 * @throws Exception 异常
	 * 2019年02月14日
	 * @author MBG
	 */
	@Override
	public String qs(String sql, Object[] uValueArrl, String splitStr) throws Exception {
		return queryString(sql,uValueArrl,false,splitStr);
	}
	//#endregion

	//#region os 获取第一条记录，将第一条记录作为字符串输出
	/**
	 * 获取第一条记录，将第一条记录作为字符串输出
	 * col1|col2|col3|col4
	 * @param sql 查询语句
	 * @param uValueArrl 提交值数组
	 * @return 记录字符串
	 * @throws Exception 异常
	 * 2016年10月17日
	 * @author MBG
	 */
	@Override
	public String os(String sql, Object[] uValueArrl) throws Exception {
		return queryString(sql,uValueArrl,true,null);
	}
	//#endregion

	//#region os 获取第一条记录，将第一条记录作为字符串输出
	/**
	 * 获取第一条记录，将第一条记录作为字符串输出
	 * col1|col2|col3|col4
	 * @param sql 查询语句
	 * @return 记录字符串
	 * @throws Exception 异常
	 * 2016年10月17日
	 * @author MBG
	 */
	@Override
	public String os(String sql) throws Exception {
		return queryString(sql,null,true,null);
	}
	//#endregion

	//#region q 查询并返回记录集序列 （用于复杂语句拼装接入）
	/**
	 * 查询并返回记录集序列 （用于复杂语句拼装接入）
	 * 
	 * @param               提交值信息
	 * @return              记录集序列
	 * @throws Exception  异常
	 * 2017年1月22日
	 * @author 马宝刚
	 */
	@Override
	@SuppressWarnings("unchecked")
	public List<Map<String,String>> q(Object[] infos) throws Exception {
		Object[] fixInfos = DBUtil.fixSqlInfo(log,infos);
		return queryList((String)fixInfos[0],(List<String>)fixInfos[1],null,null);
	}
	//#endregion

	//#region q 查询并返回记录集序列 （用于复杂语句拼装接入）
	/**
	 * 查询并返回记录集序列 （用于复杂语句拼装接入）
	 * 
	 * @param infos         提交值信息
	 * @param dicts         字典对象实例数组
	 * @return              记录集序列
	 * @throws Exception  异常
	 * 2017年1月22日
	 * @author 马宝刚
	 */
	@Override
	@SuppressWarnings("unchecked")
	public List<Map<String,String>> q(Object[] infos,Object[] dicts) throws Exception {
		Object[] fixInfos = DBUtil.fixSqlInfo(log,infos); //整理传入值
		return queryList((String)fixInfos[0],(List<String>)fixInfos[1],dicts,null);
	}
	//#endregion

	//#region q 查询并返回记录集序列 （用于复杂语句拼装接入）
	/**
	 * 查询并返回记录集序列 （用于复杂语句拼装接入）
	 * 
	 * @param infos         提交值信息
	 * @param dicts         字典对象实例数组
	 * @param rs            待插入数据的序列（如果存在该值，返回值也是该值）
	 * @return              记录集序列
	 * @throws Exception  异常
	 * 2017年1月22日
	 * @author 马宝刚
	 */
	@Override
	@SuppressWarnings("unchecked")
	public List<Map<String,String>> q(Object[] infos,Object[] dicts,List<Map<String,String>> rs) throws Exception {
		Object[] fixInfos = DBUtil.fixSqlInfo(log,infos); //整理传入值
		return queryList((String)fixInfos[0],(List<String>)fixInfos[1],dicts,rs);
	}
	//#endregion

	//#region qp 执行分页查询 （用于复杂语句拼装接入）
	/**
	 * 执行分页查询 （用于复杂语句拼装接入）
	 * @param infos 提交值信息
	 * @return 查询结果
	 * @throws Exception 异常
	 * 2017年1月22日
	 * @author MBG
	 */
	@Override
	@SuppressWarnings("unchecked")
	public QueryPageVO qp(Object[] infos) throws Exception {
		Object[] fixInfos = DBUtil.fixSqlInfo(log,infos); //整理传入值
		//构建返回值
		QueryPageVO qpVO = new QueryPageVO();
		qpVO.sql = (String)fixInfos[0];
		qpVO.uList = (List<String>)fixInfos[1];
		queryPage(qpVO);
		return qpVO;
	}
	//#endregion

	//#region qp 执行分页查询 （用于复杂语句拼装接入）
	/**
	 * 执行分页查询 （用于复杂语句拼装接入）
	 * 注意：该方法并不会返回记录集总数，也不会拼装和执行获取记录集总数的语句
	 *       该方法通常用于执行复杂SQL语句，避免拼装获取记录集总数导致执行时间过长
	 * @param pageSize     如果从会话线程中没有获取到每页记录数，则设置默认的每页记录数（避免一次性查询出大量记录导致系统崩溃）
	 * @param infos        提交值信息
	 * @return             带记录集的分页对象
	 * @throws Exception   异常
	 * 2017年9月8日
	 * @author MBG
	 */
	@Override
	@SuppressWarnings("unchecked")
	public QueryPageVO qp(int pageSize,Object[] infos) throws Exception {
		Object[] fixInfos = DBUtil.fixSqlInfo(log,infos); //整理传入值
		//构建返回值
		QueryPageVO qpVO = new QueryPageVO();
		qpVO.noFixPage = true; //标记不获取记录集总数
		if(qpVO.pageSize<1) {
			qpVO.pageSize = pageSize;
		}
		qpVO.sql = (String)fixInfos[0];
		qpVO.uList = (List<String>)fixInfos[1];
		queryPage(qpVO); //执行查询
		return qpVO;
	}
	//#endregion

	//#region qpvo 构造分页查询对象
	/**
	 * 构造分页查询对象
	 * @param infos 提交值信息
	 * @return 分页查询对象（未执行查询）
	 * @throws Exception 异常
	 * 2017年1月22日
	 * @author MBG
	 */
	@Override
	@SuppressWarnings("unchecked")
	public QueryPageVO qpvo(Object[] infos) {
		Object[] fixInfos = DBUtil.fixSqlInfo(log,infos); //整理传入值
		//构建返回值
		QueryPageVO qpVO = new QueryPageVO();
		qpVO.sql = (String)fixInfos[0];
		qpVO.uList = (List<String>)fixInfos[1];
		return qpVO;
	}
	//#endregion

	//#region qp 执行分页查询 （用于复杂语句拼装接入）
	/**
	 * 执行分页查询 （用于复杂语句拼装接入）
	 * @param infos       提交值信息
	 * @param dicts       字典对象实例数组
	 * @return            查询结果
	 * @throws Exception  异常
	 * 2017年1月22日
	 * @author MBG
	 */
	@Override
	@SuppressWarnings("unchecked")
	public QueryPageVO qp(Object[] infos,Object[] dicts) throws Exception {
		Object[] fixInfos = DBUtil.fixSqlInfo(log,infos); //整理传入值
		//构建返回值
		QueryPageVO qpVO = new QueryPageVO();
		qpVO.sql = (String)fixInfos[0];
		qpVO.uList = (List<String>)fixInfos[1];
		qpVO.dicts = dicts;
		queryPage(qpVO);
		return qpVO;
	}
	//#endregion

	//#region qs 将查询出的记录集采用这种方式输出为字符串  （用于复杂语句拼装接入）
	/**
	 * 将查询出的记录集采用这种方式输出为字符串  （用于复杂语句拼装接入）
	 *  row1_col1|row1_col2|row1_col3,row2_col1|row2_col2|row2_col3
	 *  即字段值之间用|分割，行数据之间用半角逗号分割
	 * @param infos 提交值信息
	 * @return 记录集字符串（用逗号分割）
	 * @throws Exception 异常
	 * 2017年1月22日
	 * @author MBG
	 */
	@Override
	public String qs(Object[] infos) throws Exception {
		return qs(infos,null);
	}
	//#endregion

	//#region qs 将查询出的记录集采用这种方式输出为字符串  （用于复杂语句拼装接入）
	/**
	 * 将查询出的记录集采用这种方式输出为字符串  （用于复杂语句拼装接入）
	 *  row1_col1|row1_col2|row1_col3,row2_col1|row2_col2|row2_col3
	 *  即字段值之间用|分割，行数据之间用半角逗号分割
	 * @param infos 提交值信息
	 * @param splitStr 分隔符 （为空时为半角逗号）
	 * @return 记录集字符串（用逗号分割）
	 * @throws Exception 异常
	 * 2017年1月22日
	 * @author MBG
	 */
	@Override
	@SuppressWarnings({ "unchecked"})
	public String qs(Object[] infos,String splitStr) throws Exception {
		Object[] fixInfos = DBUtil.fixSqlInfo(log,infos); //整理传入值
		//为了适应调用方法 整理传参类型
		String[] uArrl = new String[((List<String>)fixInfos[1]).size()];
		((List<String>)fixInfos[1]).toArray(uArrl);
		return queryString((String)fixInfos[0],uArrl,false,splitStr);
	}
	//#endregion

	//#region os 获取第一条记录，将第一条记录作为字符串输出 （用于复杂语句拼装接入）
	/**
	 * 获取第一条记录，将第一条记录作为字符串输出 （用于复杂语句拼装接入）
	 * col1|col2|col3|col4
	 * @param infos 提交值信息
	 * @return 记录字符串
	 * @throws Exception 异常
	 * 2017年1月22日
	 * @author MBG
	 */
	@Override
	@SuppressWarnings({ "unchecked"})
	public String os(Object[] infos) throws Exception {
		Object[] fixInfos = DBUtil.fixSqlInfo(log,infos); //整理传入值
		//为了适应调用方法 整理传参类型
		String[] uArrl = new String[((List<String>)fixInfos[1]).size()];
		((List<String>)fixInfos[1]).toArray(uArrl);
		return queryString((String)fixInfos[0],uArrl,true,null);
	}
	//#endregion

	//#region o 查询结果并返回第一条记录 （用于复杂语句拼装接入）
	/**
	 * 查询结果并返回第一条记录 （用于复杂语句拼装接入）
	 * @param infos             提交值信息
	 * @return                  记录集行对象
	 * @throws Exception        异常
	 * 2017年1月22日
	 * @author 马宝刚
	 */
	@Override
	@SuppressWarnings("unchecked")
	public Map<String,String> o(Object[] infos) throws Exception {
		Object[] fixInfos = DBUtil.fixSqlInfo(log,infos); //整理传入值
		return queryOne((String)fixInfos[0],(List<String>)fixInfos[1],null);
	}
	//#endregion

	//#region o 查询结果并返回第一条记录 （用于复杂语句拼装接入）
	/**
	 * 查询结果并返回第一条记录 （用于复杂语句拼装接入）
	 * @param infos             提交值信息
	 * @param dicts             数据字典类序列
	 * @return                  记录集行对象
	 * @throws Exception        异常
	 * 2014-3-8
	 * @author 马宝刚
	 */
	@Override
	@SuppressWarnings("unchecked")
	public Map<String,String> o(Object[] infos,Object[] dicts) throws Exception {
		Object[] fixInfos = DBUtil.fixSqlInfo(log,infos); //整理传入值
		return queryOne((String)fixInfos[0],(List<String>)fixInfos[1],dicts);
	}
	//#endregion

	//#region e 执行更新 （用于复杂语句拼装接入）
	/**
	 * 执行更新 （用于复杂语句拼装接入）
	 * @param infos             提交值信息
	 * @return                  返回更新状态
	 * @throws Exception        异常
	 * 2014-3-8
	 * @author 马宝刚
	 */
	@Override
	@SuppressWarnings("unchecked")
	public int e(Object[] infos) throws Exception {
		Object[] fixInfos = DBUtil.fixSqlInfo(log,infos); //整理传入值
		return executeUpdate((String)fixInfos[0],(List<String>)fixInfos[1]);
	}
	//#endregion

	//#region qp 执行分页查询（用于复杂语句拼装接入）
	/**
	 * 执行分页查询（用于复杂语句拼装接入）
	 * @param pageNo      指定页号
	 * @param pageSize    每页记录数
	 * @param infos       提交值信息
	 * @return            查询结果
	 * @throws Exception  异常
	 * 2018年8月1日
	 * @author MBG
	 */
	@Override
	@SuppressWarnings("unchecked")
	public QueryPageVO qp(int pageNo,int pageSize,Object[] infos) throws Exception {
		Object[] fixInfos = DBUtil.fixSqlInfo(log,infos); //整理传入值
		//构建返回值
		QueryPageVO qpVO = new QueryPageVO();
		qpVO.sql         = (String)fixInfos[0];
		qpVO.uList       = (List<String>)fixInfos[1];
		if(pageNo<1) {
			pageNo = 1;
		}
		qpVO.pageNo = pageNo;
		if(pageSize==0) {
			pageSize = 10;
			qpVO.pageSize = 10;
		}else if(pageSize<0) {
			//pageSize小于0时不做分页处理
			qpVO.pageSize  = -1;
			qpVO.noFixPage = true;
		}else {
			qpVO.pageSize = pageSize;
		}
		queryPage(qpVO);
		return qpVO;
	}
	//#endregion

	//#region qp 执行分页查询 （用于复杂语句拼装接入）
	/**
	 * 执行分页查询 （用于复杂语句拼装接入）
	 * @param pageNo        页号
	 * @param pageSize      每页记录数
	 * @param infos         提交值信息
	 * @param dicts         字典对象实例数组
	 * @return              查询结果
	 * @throws Exception    异常
	 * 2017年1月22日
	 * @author MBG
	 */
	@Override
	@SuppressWarnings("unchecked")
	public QueryPageVO qp(int pageNo,int pageSize,Object[] infos,Object[] dicts) throws Exception {
		Object[] fixInfos = DBUtil.fixSqlInfo(log,infos); //整理传入值
		//构建返回值
		QueryPageVO qpVO = new QueryPageVO();
		qpVO.sql = (String)fixInfos[0];
		qpVO.uList = (List<String>)fixInfos[1];
		qpVO.dicts = dicts;
		if(pageNo<1) {
			pageNo = 1;
		}
		qpVO.pageNo = pageNo;
		if(pageSize==0) {
			pageSize = 10;
			qpVO.pageSize = 10;
		}else if(pageSize<0) {
			//pageSize小于0时不做分页处理
			qpVO.pageSize  = -1;
			qpVO.noFixPage = true;
		}else {
			qpVO.pageSize = pageSize;
		}
		queryPage(qpVO);
		return qpVO;
	}
	//#endregion

	//#region getDbs 获取数据操作服务
	/**
	 * 获取数据操作服务
	 * @return 数据操作服务
	 * @throws Exception 异常
	 * 2014年9月24日
	 * @author 马宝刚
	 */
	@Override
	public DBQuerySvc getDbs() {
		if(dbs==null) {
			if(getBeanFactory().beanExists(DBQuerySvc.class)) {
				dbs = bean(DBQuerySvc.class);
			}else {
				dbs = new DBQuerySvc();
				dbs.setBase(this);
				try {
					getBeanFactory().setObject(DBQuerySvc.class,dbs);
				}catch(Exception e) {
					e.printStackTrace();
				}
			}
			//数据库配置信息容器
			Map<String,Map<String,String>> infoMap = getDataManager().getElementInfoMap();
			//设置别名信息
			List<String> keyList = BaseUtil.getMapKeyList(infoMap);
			Map<String,String> infoEle; //指定数据源配置信息容器
			String sourceKey; //源数据源主键
			for(String key:keyList) {
				infoEle = infoMap.get(key);
				if(infoEle==null) {
					continue;
				}
				sourceKey = str(infoEle.get("db_source"));
				if(sourceKey.length()>0) {
					dbs.sourceKeyMap.put(key,sourceKey);
				}
			}
		}
		return dbs;
	}
	//#endregion

	//#region getTableName 从更新数据的sql中获取表名
	/**
	 * 从更新数据的sql中获取表名
	 * @param sql 更新数据的sql语句
	 * @return    对应的表明
	 * 2019年6月18日
	 * @author MBG
	 */
	public String getTableName(String sql) {
		if(sql==null) {
			return "";
		}
		int    point;     //字符串截取位置
		int    ePoint;    // 结束字符位置
		sql = sql.toLowerCase().trim();
		if(sql.startsWith("insert")) {
			point = sql.indexOf(" into ");
			if(point>0) {
				ePoint = sql.indexOf("(");
				if(ePoint<1) {
					// insert 语句未必有括号，比如 insert into table select * from table 
					return "";
				}
				return sql.substring(point+6,ePoint).trim();
			}
		}else if(sql.startsWith("update")) {
			point = sql.indexOf(" set");
			if(point<0) {
				return "";
			}
			sql = sql.substring(0,point);
			point = sql.indexOf(" from ");
			if(point<0) {
				return sql.substring(7).trim();
			}
			return sql.substring(point+6).trim();
		}else if(sql.startsWith("delete")) {
			point = sql.indexOf(" where ");
			if(point>0) {
				sql = sql.substring(0,point);
			}
			point = sql.indexOf(" from ");
			if(point<0) {
				return sql.substring(7).trim();
			}
			return sql.substring(point+6).trim();
		}
		return "";
	}
	//#endregion
}


